Initial open source commit.

This commit is contained in:
GRMrGecko 2015-06-03 16:34:31 -05:00
commit e5db00ae3d
349 changed files with 44918 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
build
*.zip
*.xcodeproj/*.pbxuser
*.xcodeproj/*.mode*
*.xcodeproj/*.perspective*
*.xcodeproj/xcuserdata
*.xcodeproj/project.xcworkspace/xcuserdata
*.xcworkspace/xcuserdata
YouView/*.app
*.app
Screenshots

20
About.rtf Normal file
View File

@ -0,0 +1,20 @@
{\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf570
\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc
\f0\fs32 \cf0 Special Thanks To\
\fs24 MegaEduX ({\field{\*\fldinst{HYPERLINK "http://megaedux.com"}}{\fldrslt megaedux.com}})\
RockStar ({\field{\*\fldinst{HYPERLINK "http://rocknthesweater.com"}}{\fldrslt rocknthesweater.com}})\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
\cf0 YouView Uses {\field{\*\fldinst{HYPERLINK "http://ffmpeg.org"}}{\fldrslt FFmpeg}} for converting video, {\field{\*\fldinst{HYPERLINK "http://mediainfo.sourceforge.net"}}{\fldrslt mediainfo}} to determine information about video, {\field{\*\fldinst{HYPERLINK "http://sparkle.andymatuschak.org"}}{\fldrslt Sparkle}} for software update, and {\field{\*\fldinst{HYPERLINK "http://code.google.com/apis/gdata/"}}{\fldrslt GData}} for gathering information.\
\
Browse, watch, convert, and download YouTube videos on your Mac faster, because YouView uses the core technologies of Mac OS X to play instead of Flash allowing video to run smoother on systems with lower specs.\
YouView contains great parental controls that'll allow any parents control what their children see on YouTube via filters such as Safe search and flagged videos. By default YouView is moderate on parental controls but can be strict if needed.\
YouView allows you to choose the max size of video that is loaded such as 1080P. By default it is 480P but can go all the way up to 4k if you system supports it.\
When logged in with YouView you have the ability to view your special feeds such as recommendations which shows videos that YouTube thinks you may also like based on your history of viewing.\
There is a lot more to YouView than described here, the best way to find out what you can do is to try it out your self.\
I require donations for download/converting of video as it isn't an easy task to get together.}

View File

@ -0,0 +1,17 @@
//
// MGMYVTool.h
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MGMYVTool : NSObject {
pid_t parentProcessId;
NSTimer *shutdownCheck;
}
- (id)initWithPid:(pid_t)thePid;
@end

View File

@ -0,0 +1,54 @@
//
// MGMYVTool.m
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMYVTool.h"
@implementation MGMYVTool
- (id)initWithPid:(pid_t)thePid {
if (self = [super init]) {
parentProcessId = thePid;
shutdownCheck = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkProcess) userInfo:nil repeats:YES] retain];
}
return self;
}
- (void)dealloc {
[shutdownCheck invalidate];
[shutdownCheck release];
[super dealloc];
}
- (void)checkProcess {
ProcessSerialNumber psn;
if (GetProcessForPID(parentProcessId, &psn) == procNotFound) {
exit(0);
}
}
- (void)shouldQuit {
exit(0);
}
- (void)changePremissionsForPath:(NSString *)thePath to:(NSString *)thePermissions {
NSTask *task = [[NSTask new] autorelease];
[task setLaunchPath:@"/bin/chmod"];
[task setArguments:[NSArray arrayWithObjects:thePermissions, thePath, nil]];
[task launch];
[task waitUntilExit];
}
- (void)changeOwnerForPath:(NSString *)thePath to:(NSString *)theOwner {
NSTask *task = [[NSTask new] autorelease];
[task setLaunchPath:@"/usr/sbin/chown"];
[task setArguments:[NSArray arrayWithObjects:theOwner, thePath, nil]];
[task launch];
[task waitUntilExit];
}
- (void)quit {
[shutdownCheck invalidate];
[shutdownCheck release];
shutdownCheck = [[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(shouldQuit) userInfo:nil repeats:NO] retain];
}
@end

36
Classes/YVTool/main.m Normal file
View File

@ -0,0 +1,36 @@
//
// main.m
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "MGMYVTool.h"
MGMYVTool *yvServer;
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
yvServer = [[MGMYVTool alloc] initWithPid:atoi(argv[1])];
NSConnection *theYVServer = [NSConnection new];
if(theYVServer==nil) {
NSLog(@"Server couldn't start");
exit(1);
}
[theYVServer setRootObject:yvServer];
[theYVServer registerName:@"MGMYVServer"];
[theYVServer setDelegate:yvServer];
NSLog(@"Server Started");
[[NSRunLoop currentRunLoop] run];
[yvServer release];
[theYVServer release];
[pool release];
return 0;
}

View File

@ -0,0 +1,29 @@
//
// NSAddons.h
// YouView
//
// Created by Mr. Gecko on 3/4/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface NSString (MGMAddons)
+ (NSString *)stringWithSeconds:(int)seconds;
- (NSString *)flattenHTML;
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString;
- (BOOL)containsString:(NSString *)string;
- (NSString *)addPercentEscapes;
- (NSString *)URLParameterWithName:(NSString *)theName;
- (NSDictionary *)URLParameters;
@end
@interface NSURL (MGMAddons)
- (NSString *)URLParameterWithName:(NSString *)theName;
- (NSDictionary *)URLParameters;
- (NSURL *)URLByAppendingPathComponent:(NSString *)theComponent;
@end
@interface NSUserDefaults (MGMAddons)
+ (void)registerDefaults;
@end

164
Classes/YouView/MGMAddons.m Normal file
View File

@ -0,0 +1,164 @@
//
// NSAddons.m
// YouView
//
// Created by Mr. Gecko on 3/4/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMAddons.h"
#import "MGMController.h"
#import "MGMXML.h"
#import <GeckoReporter/MGMLog.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <CommonCrypto/CommonDigest.h>
#import <openssl/evp.h>
#import <openssl/rand.h>
#import <openssl/rsa.h>
#import <openssl/engine.h>
#import <openssl/sha.h>
#import <openssl/pem.h>
#import <openssl/bio.h>
#import <openssl/err.h>
#import <openssl/ssl.h>
@implementation NSString (MGMAddons)
+ (NSString *)stringWithSeconds:(int)time {
int seconds = time%60;
time = time/60;
int minutes = time%60;
time = time/60;
int hours = time%24;
int days = time/24;
NSString *string;
if (days!=0) {
string = [NSString stringWithFormat:@"%d:%02d:%02d:%02d", days, hours, minutes, seconds];
} else if (hours!=0) {
string = [NSString stringWithFormat:@"%d:%02d:%02d", hours, minutes, seconds];
} else {
string = [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
}
return string;
}
//Remove html
- (NSString *)flattenHTML {
NSString *xml = [NSString stringWithFormat:@"<div>%@</div>", self];
MGMXMLDocument *document = [[MGMXMLDocument alloc] initWithXMLString:xml options:MGMXMLDocumentTidyHTML error:nil];
MGMXMLElement *element = nil;
if (document!=nil) {
element = [[[document rootElement] retain] autorelease];
if (element!=nil)
[element detach];
[document release];
}
return [element stringValue];
}
//Replace
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSMutableString *temp = [NSMutableString new];
NSRange replaceRange = NSMakeRange(0, [self length]);
NSRange rangeInOriginalString = replaceRange;
int replaced = 0;
while (1) {
NSRange rangeToCopy;
NSRange foundRange = [self rangeOfString:targetString options:0 range:rangeInOriginalString];
if (foundRange.length == 0) break;
rangeToCopy = NSMakeRange(rangeInOriginalString.location, foundRange.location - rangeInOriginalString.location);
[temp appendString:[self substringWithRange:rangeToCopy]];
[temp appendString:replaceString];
rangeInOriginalString.length -= NSMaxRange(foundRange) -
rangeInOriginalString.location;
rangeInOriginalString.location = NSMaxRange(foundRange);
replaced++;
if (replaced % 100 == 0) {
[pool release];
pool = [NSAutoreleasePool new];
}
}
if (rangeInOriginalString.length > 0) [temp appendString:[self substringWithRange:rangeInOriginalString]];
[pool release];
return [temp autorelease];
}
- (BOOL)containsString:(NSString *)string {
return ([[self lowercaseString] rangeOfString:[string lowercaseString]].location != NSNotFound);
}
- (NSString *)addPercentEscapes {
NSString *result = [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR("!*'();:^@&=+$,/?%#[]|"), kCFStringEncodingUTF8);
if (escapedString!=NULL)
result = [(NSString *)escapedString autorelease];
return result;
}
- (NSString *)URLParameterWithName:(NSString *)theName {
NSArray *parameters = [self componentsSeparatedByString:@"&"];
for (int i=0; i<[parameters count]; i++) {
NSArray *parameter = [[parameters objectAtIndex:i] componentsSeparatedByString:@"="];
if ([[parameter objectAtIndex:0] isEqual:theName])
return [[parameter objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
return nil;
}
- (NSDictionary *)URLParameters {
NSArray *parameters = [self componentsSeparatedByString:@"&"];
NSMutableDictionary *returnParameters = [NSMutableDictionary dictionary];
for (int i=0; i<[parameters count]; i++) {
NSArray *parameter = [[parameters objectAtIndex:i] componentsSeparatedByString:@"="];
[returnParameters setObject:[[parameter objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[parameter objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
return returnParameters;
}
@end
@implementation NSURL (MGMAddons)
- (NSString *)URLParameterWithName:(NSString *)theName {
NSArray *parameters = [[self query] componentsSeparatedByString:@"&"];
for (int i=0; i<[parameters count]; i++) {
NSArray *parameter = [[parameters objectAtIndex:i] componentsSeparatedByString:@"="];
if ([[parameter objectAtIndex:0] isEqual:theName])
return [[parameter objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
return nil;
}
- (NSDictionary *)URLParameters {
NSArray *parameters = [[self query] componentsSeparatedByString:@"&"];
NSMutableDictionary *returnParameters = [NSMutableDictionary dictionary];
for (int i=0; i<[parameters count]; i++) {
NSArray *parameter = [[parameters objectAtIndex:i] componentsSeparatedByString:@"="];
[returnParameters setObject:[[parameter objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[parameter objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
return returnParameters;
}
- (NSURL *)URLByAppendingPathComponent:(NSString *)theComponent {
NSString *path = [self path];
path = [path stringByAppendingPathComponent:theComponent];
NSString *url = [NSString stringWithFormat:@"%@://%@%@?%@", [self scheme], [self host], path, [self query]];
return [NSURL URLWithString:url];
}
@end
@implementation NSUserDefaults (MGMAddons)
+ (void)registerDefaults {
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMMaxQuality];
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMWindowMode];
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MGMAnimations];
[defaults setObject:[NSNumber numberWithBool:NO] forKey:MGMFSFloat];
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MGMFSSpaces];
[defaults setObject:[NSNumber numberWithInt:50] forKey:MGMPageMax];
[defaults setObject:[NSArray array] forKey:MGMRecentSearches];
[defaults setObject:[NSNumber numberWithInt:1] forKey:MGMOrderBy];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
}
@end

View File

@ -0,0 +1,24 @@
//
// MGMAdminAction.h
// YouView
//
// Created by Mr. Gecko on 3/25/08.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <Security/Authorization.h>
#import <Security/AuthorizationTags.h>
@interface MGMAdminAction : NSObject {
AuthorizationRef authorization;
BOOL authorizationSetByUs;
}
- (void)setAuthorization:(AuthorizationRef)theAuthorization;
+ (AuthorizationRights)rightsForCommands:(NSArray *)theCommands;
- (BOOL)isAuthenticated:(NSArray *)theCommands;
- (BOOL)fetchPassword:(NSArray *)theCommands;
- (BOOL)authenticate:(NSArray *)theCommands;
- (NSString *)executeCommand:(NSString *)pathToCommand withArguments:(NSArray *)arguments;
- (void)launchCommand:(NSString *)thePath withArguments:(NSArray *)theArguments;
@end

View File

@ -0,0 +1,165 @@
//
// MGMAdminAction.m
// YouView
//
// Created by Mr. Gecko on 3/25/08.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMAdminAction.h"
#import <Security/AuthorizationTags.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/socket.h>
@implementation MGMAdminAction
- (id)init {
if (self = [super init]) {
authorization = NULL;
authorizationSetByUs = YES;
}
return self;
}
- (void)dealloc {
if (authorization!=NULL && authorizationSetByUs)
AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
[super dealloc];
}
- (void)setAuthorization:(AuthorizationRef)theAuthorization {
if (authorization!=NULL && authorizationSetByUs)
AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
authorization = theAuthorization;
authorizationSetByUs = NO;
}
+ (AuthorizationRights)rightsForCommands:(NSArray *)theCommands {
AuthorizationItem *items = malloc(sizeof(AuthorizationItem) *[theCommands count]);
for (int i=0; i<[theCommands count]; i++) {
items[i].name = kAuthorizationRightExecute;
items[i].value = (char *)[[theCommands objectAtIndex:i] UTF8String];
items[i].valueLength = [[theCommands objectAtIndex:i] length];
items[i].flags = 0;
}
AuthorizationRights rights;
rights.count = [theCommands count];
rights.items = items;
return rights;
}
- (AuthorizationRights)rightsForCommands:(NSArray *)theCommands {
return [[self class] rightsForCommands:theCommands];
}
- (BOOL)isAuthenticated:(NSArray *)theCommands {
AuthorizationRights rights;
AuthorizationRights *authorizedRights;
OSStatus status;
if (theCommands==nil || [theCommands count]==0)
return NO;
if (authorization==NULL) {
rights.count=0;
rights.items = NULL;
status = AuthorizationCreate(&rights, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorization);
}
rights = [self rightsForCommands:theCommands];
status = AuthorizationCopyRights(authorization, &rights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights, &authorizedRights);
free(rights.items);
if (status==errAuthorizationSuccess) {
AuthorizationFreeItemSet(authorizedRights);
}
return (status==errAuthorizationSuccess);
}
- (BOOL)fetchPassword:(NSArray *)theCommands {
if (theCommands==nil || [theCommands count]==0)
return NO;
AuthorizationRights rights = [self rightsForCommands:theCommands];
OSStatus status = AuthorizationCopyRights(authorization, &rights, kAuthorizationEmptyEnvironment, kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights, NULL);
free(rights.items);
return (status==errAuthorizationSuccess);
}
- (BOOL)authenticate:(NSArray *)theCommands {
if (![self isAuthenticated:theCommands]) {
[self fetchPassword:theCommands];
}
return [self isAuthenticated:theCommands];
}
- (NSString *)executeCommand:(NSString *)thePath withArguments:(NSArray *)theArguments {
char *args[30];
int status;
FILE *pipe = NULL;
NSString *output = nil;
if (![self authenticate:[NSArray arrayWithObject:thePath]])
return nil;
if (theArguments==nil || [theArguments count]==0) {
args[0] = NULL;
} else {
for (int i=0; i<[theArguments count]; i++) {
args[i] = (char *)[[theArguments objectAtIndex:i] UTF8String];
args[i+1] = NULL;
}
}
status = AuthorizationExecuteWithPrivileges(authorization, [thePath UTF8String], kAuthorizationFlagDefaults, args, &pipe);
NSMutableData *outputData = [NSMutableData data];
NSMutableData *tempData = [NSMutableData dataWithLength:512];
int len;
if (pipe!=NULL) {
do {
[tempData setLength:512];
len = fread([tempData mutableBytes], 1, 512, pipe);
if (len>0) {
[tempData setLength:len];
[outputData appendData:tempData];
}
} while (len==512);
}
if ([outputData length]!=0)
output = [[[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding] autorelease];
if (status!=0) {
NSLog(@"Error %d in AuthorizationExecuteWithPrivileges", status);
}
return output;
}
- (void)launchCommand:(NSString *)thePath withArguments:(NSArray *)theArguments {
char *args[30];
int status;
if (![self authenticate:[NSArray arrayWithObject:thePath]])
return;
if (theArguments==nil || [theArguments count]==0) {
args[0] = NULL;
} else {
for (int i=0; i<[theArguments count]; i++) {
args[i] = (char *)[[theArguments objectAtIndex:i] UTF8String];
args[i+1] = NULL;
}
}
status = AuthorizationExecuteWithPrivileges(authorization, [thePath UTF8String], kAuthorizationFlagDefaults, args, NULL);
if (status!=0) {
NSLog(@"Error %d in AuthorizationExecuteWithPrivileges", status);
}
}
@end

View File

@ -0,0 +1,123 @@
//
// Controller.h
// YouView
//
// Created by Mr. Gecko on 1/17/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#define youviewdebug 1
#define releaseDebug 0
extern NSString * const MGMUserAgent;
extern NSString * const MGMSafeSearch;
extern NSString * const MGMAllowFlaggedVideos;
extern NSString * const MGMSalt1;
extern NSString * const MGMSalt2;
extern NSString * const MGMDonationPath;
extern NSString * const MGMRecentSearchesChangeNotification;
extern NSString * const MGMRecentSearches;
extern NSString * const MGMSubscriptionFile;
extern NSString * const MGMIAuthor;
extern NSString * const MGMITitle;
extern NSString * const MGMIViews;
extern NSString * const MGMIFavorites;
extern NSString * const MGMIRating;
extern NSString * const MGMIAdded;
extern NSString * const MGMITime;
extern NSString * const MGMIKeywords;
extern NSString * const MGMIDescription;
extern NSString * const MGMAnimations;
extern NSString * const MGMFSFloat;
extern NSString * const MGMFSSpaces;
extern NSString * const MGMFSSettingsNotification;
extern NSString * const MGMPageMax;
extern NSString * const MGMOrderBy;
extern NSString * const MGMRelevance;
extern NSString * const MGMPublished;
extern NSString * const MGMViewCount;
extern NSString * const MGMRating;
extern NSString * const MGMMaxQuality;
extern NSString * const MGMWindowMode;
extern NSString * const MGMYTURL;
extern NSString * const MGMYTSDURL;
extern NSString * const MGMYTImageURL;
@class WebView, MGMTaskManager, MGMPlayer, RemoteControlContainer, MultiClickRemoteBehavior, MGMPreferences;
@interface MGMController : NSObject {
//Essentials
NSMutableDictionary *subscriptionsDate;
//Apple Remote
NSTimer *holding;
RemoteControlContainer *remoteControl;
MultiClickRemoteBehavior *remoteControlBehavior;
//About
IBOutlet NSWindow *aboutWin;
IBOutlet NSTextField *aboutTitle;
//Prefences
MGMPreferences *preferences;
//Sorting
IBOutlet NSMenuItem *relevance;
IBOutlet NSMenuItem *published;
IBOutlet NSMenuItem *viewCount;
IBOutlet NSMenuItem *rating;
int orderBy;
//Open
IBOutlet NSWindow *openWindow;
IBOutlet NSTextField *openField;
IBOutlet NSButton *openButton;
NSString *openURL;
//Task
IBOutlet MGMTaskManager *taskManager;
NSMutableArray *players;
int currPlayer;
NSMutableArray *recentSearches;
NSTimer *systemStatusTimer;
BOOL openingURL;
}
- (void)setup;
- (NSArray *)recentSearches;
- (void)addRecentSearch:(NSString *)theSearch;
- (void)clearRecentSearches;
- (NSMutableDictionary *)subscriptionsDate;
- (NSString *)orderBy;
- (int)orderByNum;
- (IBAction)sourceCode:(id)sender;
- (IBAction)donate:(id)sender;
- (IBAction)installSafari:(id)sender;
- (IBAction)installSafariExt:(id)sender;
- (IBAction)installChrome:(id)sender;
- (IBAction)installFirefox:(id)sender;
- (void)holding:(NSTimer *)theTimer;
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
- (IBAction)showOpenPanel:(id)sender;
- (IBAction)loop:(id)sender;
- (IBAction)openURL:(id)sender;
- (void)openVideo:(NSURL *)theVideo;
- (void)playerClosed:(MGMPlayer *)player;
- (void)playerBecameKey:(MGMPlayer *)player;
- (IBAction)goFullScreen:(id)sender;
- (IBAction)newWindow:(id)sender;
- (IBAction)copyURL:(id)sender;
- (IBAction)about:(id)sender;
- (IBAction)preferences:(id)sender;
- (void)setOrder:(int)order;
- (IBAction)setOrderBy:(id)sender;
- (void)setIcon:(NSImage *)preview;
- (IBAction)saveVideo:(id)sender;
- (NSURL *)generateAPIURL:(NSString *)path arguments:(NSMutableDictionary *)arguments;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
//
// MGMNotifications.h
// YouView
//
// Created by Mr. Gecko on 11/11/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MGMNotifications : NSObject {
}
+ (void)startNotifications;
+ (void)stopNotifications;
- (void)distributedNotifications:(NSNotification *)notification;
- (void)selfNotifications:(NSNotification *)notification;
@end

View File

@ -0,0 +1,47 @@
//
// MGMNotifications.m
// YouView
//
// Created by Mr. Gecko on 11/11/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMNotifications.h"
static MGMNotifications *MGMNotificationsSingleton = nil;
@implementation MGMNotifications
+ (void)startNotifications {
@synchronized(self) {
if (MGMNotificationsSingleton == nil) {
MGMNotificationsSingleton = [[self alloc] init];
}
}
}
+ (void)stopNotifications {
@synchronized(self) {
if (MGMNotificationsSingleton != nil) {
[MGMNotificationsSingleton release];
}
}
}
- (id)init {
if (self = [super init]) {
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(distributedNotifications:) name:nil object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(selfNotifications:) name:nil object:nil];
}
return self;
}
- (void)dealloc {
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)distributedNotifications:(NSNotification *)notification {
NSLog(@"Distributed Notification: %@\n%@", [notification name], [notification userInfo]);
}
- (void)selfNotifications:(NSNotification *)notification {
NSLog(@"Notification: %@\n%@", [notification name], [notification userInfo]);
}
@end

View File

@ -0,0 +1,25 @@
//
// MGMParentalControls.h
// YouView
//
// Created by Mr. Gecko on 4/25/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MGMParentalControls : NSObject {
NSMutableDictionary *parentalControls;
NSString *masterKey;
}
+ (id)standardParentalControls;
- (NSString *)path;
- (NSData *)encrypt:(NSString *)string withKey:(NSString *)key;
- (NSString *)decrypt:(NSData *)encryptedData withKey:(NSString *)key;
- (void)setString:(NSString *)object forKey:(NSString *)key;
- (NSString *)stringForKey:(NSString *)key;
- (void)setBool:(BOOL)object forKey:(NSString *)key;
- (BOOL)boolForKey:(NSString *)key;
- (void)save;
@end

View File

@ -0,0 +1,188 @@
//
// MGMParentalControls.m
// YouView
//
// Created by Mr. Gecko on 4/25/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMParentalControls.h"
#import "MGMController.h"
#import "MGMAddons.h"
#import <MGMUsers/MGMUsers.h>
#import <GeckoReporter/GeckoReporter.h>
#import <CommonCrypto/CommonDigest.h>
#import <openssl/evp.h>
#import <openssl/rand.h>
#import <openssl/rsa.h>
#import <openssl/engine.h>
#import <openssl/sha.h>
#import <openssl/pem.h>
#import <openssl/bio.h>
#import <openssl/err.h>
#import <openssl/ssl.h>
NSString * const MGMKey = @"LJlmlj832jfs";
NSString * const MGMParentalPath = @".parental.plist";
NSString * const MGMMasterKey = @"PCMasterKey";
@implementation MGMParentalControls
+ (id)standardParentalControls {
return [[[self alloc] init] autorelease];
}
- (id)init {
if (self = [super init]) {
if ([[NSFileManager defaultManager] fileExistsAtPath:[[self path] stringByExpandingTildeInPath]]) {
parentalControls = [[NSMutableDictionary dictionaryWithContentsOfFile:[[self path] stringByExpandingTildeInPath]] retain];
masterKey = [[self decrypt:[[NSUserDefaults standardUserDefaults] objectForKey:MGMMasterKey] withKey:MGMKey] retain];
} else {
parentalControls = [NSMutableDictionary new];
srandomdev();
masterKey = [[[NSString stringWithFormat:@"%d", random()] MD5] retain];
[[NSUserDefaults standardUserDefaults] setObject:[self encrypt:masterKey withKey:MGMKey] forKey:MGMMasterKey];
[self setBool:NO forKey:MGMAllowFlaggedVideos];
[self setString:@"moderate" forKey:MGMSafeSearch];
}
}
return self;
}
- (void)dealloc {
#if releaseDebug
MGMLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
[parentalControls release];
[masterKey release];
[super dealloc];
}
- (NSString *)path {
return [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMParentalPath];
}
- (NSData *)encrypt:(NSString *)string withKey:(NSString *)key {
OpenSSL_add_all_algorithms();
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
unsigned char *input = (unsigned char *)[data bytes];
unsigned char *outbuf, iv[EVP_MAX_IV_LENGTH];
int outlen, templen, inlen;
inlen = [data length];
if(inlen==0)
return nil;
//Key
unsigned char evp_key[EVP_MAX_KEY_LENGTH] = {"\0"};
EVP_CIPHER_CTX cCtx;
const EVP_CIPHER *cipher;
cipher = EVP_get_cipherbyname("aes128");
if (!cipher){
MGMLog(@"cannot get cipher with name aes128");
return nil;
}
EVP_BytesToKey(cipher, EVP_md5(), NULL, (unsigned char *)[key UTF8String], [key length], 1, evp_key, iv);
EVP_CIPHER_CTX_init(&cCtx);
if (!EVP_EncryptInit(&cCtx, cipher, evp_key, iv)) {
MGMLog(@"EVP_EncryptInit() failed!");
EVP_CIPHER_CTX_cleanup(&cCtx);
return nil;
}
EVP_CIPHER_CTX_set_key_length(&cCtx, EVP_MAX_KEY_LENGTH);
//Encrypt
outbuf = (unsigned char *)calloc(inlen + EVP_CIPHER_CTX_block_size(&cCtx), sizeof(unsigned char));
NSAssert(outbuf, @"Cannot allocate memory for buffer!");
if (!EVP_EncryptUpdate(&cCtx, outbuf, &outlen, input, inlen)){
MGMLog(@"EVP_EncryptUpdate() failed!");
EVP_CIPHER_CTX_cleanup(&cCtx);
return nil;
}
if (!EVP_EncryptFinal(&cCtx, outbuf + outlen, &templen)){
MGMLog(@"EVP_EncryptFinal() failed!");
EVP_CIPHER_CTX_cleanup(&cCtx);
return nil;
}
outlen += templen;
EVP_CIPHER_CTX_cleanup(&cCtx);
NSData *returnData = [NSData dataWithBytes:outbuf length:outlen];
free(outbuf);
return returnData;
}
- (NSString *)decrypt:(NSData *)encryptedData withKey:(NSString *)key {
OpenSSL_add_all_algorithms();
unsigned char *outbuf, iv[EVP_MAX_IV_LENGTH];
int outlen, templen, inlen;
inlen = [encryptedData length];
unsigned char *input = (unsigned char *)[encryptedData bytes];
unsigned char evp_key[EVP_MAX_KEY_LENGTH] = {"\0"};
EVP_CIPHER_CTX cCtx;
const EVP_CIPHER *cipher;
cipher = EVP_get_cipherbyname("aes128");
if(!cipher)
{
MGMLog(@"cannot get cipher with name aes128");
return nil;
}
EVP_BytesToKey(cipher, EVP_md5(), NULL, (unsigned char *)[key UTF8String], [key length], 1, evp_key, iv);
EVP_CIPHER_CTX_init(&cCtx);
if (!EVP_DecryptInit(&cCtx, cipher, evp_key, iv)) {
MGMLog(@"EVP_DecryptInit() failed!");
EVP_CIPHER_CTX_cleanup(&cCtx);
return nil;
}
EVP_CIPHER_CTX_set_key_length(&cCtx, EVP_MAX_KEY_LENGTH);
outbuf = (unsigned char *)calloc(inlen+32, sizeof(unsigned char));
NSAssert(outbuf, @"Cannot allocate memory for buffer!");
//Decrypt
if (!EVP_DecryptUpdate(&cCtx, outbuf, &outlen, input, inlen)){
MGMLog(@"EVP_DecryptUpdate() failed!");
EVP_CIPHER_CTX_cleanup(&cCtx);
return nil;
}
if (!EVP_DecryptFinal(&cCtx, outbuf + outlen, &templen)){
MGMLog(@"EVP_DecryptFinal() failed!");
EVP_CIPHER_CTX_cleanup(&cCtx);
return nil;
}
outlen += templen;
EVP_CIPHER_CTX_cleanup(&cCtx);
NSString *returnString = [[[NSString alloc] initWithData:[NSData dataWithBytes:outbuf length:outlen] encoding:NSUTF8StringEncoding] autorelease];
free(outbuf);
return returnString;
}
- (void)setString:(NSString *)object forKey:(NSString *)key {
[parentalControls setObject:[self encrypt:object withKey:masterKey] forKey:key];
[self save];
}
- (NSString *)stringForKey:(NSString *)key {
if ([parentalControls objectForKey:key]!=nil)
return [self decrypt:[parentalControls objectForKey:key] withKey:masterKey];
return nil;
}
- (void)setBool:(BOOL)object forKey:(NSString *)key {
if (object)
[parentalControls setObject:[self encrypt:@"YES" withKey:masterKey] forKey:key];
else
[parentalControls setObject:[self encrypt:@"NO" withKey:masterKey] forKey:key];
[self save];
}
- (BOOL)boolForKey:(NSString *)key {
return [[self decrypt:[parentalControls objectForKey:key] withKey:masterKey] isEqual:@"YES"];
}
- (void)save {
[parentalControls writeToFile:[self path] atomically:YES];
}
@end

View File

@ -0,0 +1,45 @@
//
// MGMVideoFinder.h
// YouView
//
// Created by Mr. Gecko on 8/3/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@protocol MGMVideoFinderDelegate
- (void)loadFlash:(NSDictionary *)info;
- (void)loadVideo:(NSDictionary *)info;
@end
extern NSString * const MGMVLVideoURLKey;
extern NSString * const MGMVLAudioURLKey;
extern NSString * const MGMVLURLKey;
extern NSString * const MGMVLTitle;
extern NSString * const MGMVLVersion;
@class MGMURLConnectionManager;
@interface MGMVideoFinder : NSObject {
id<MGMVideoFinderDelegate> delegate;
int maxQuality;
NSURL *URL;
MGMURLConnectionManager *connectionManager;
NSMutableArray *videoURLS;
NSString *title;
NSString *version;
BOOL requestingSD;
NSMutableDictionary *videoQualities;
}
- (id)initWithURL:(NSURL *)theURL connectionManager:(MGMURLConnectionManager *)theConnectionManager maxQuality:(int)theMaxQuality delegate:(id)theDelegate;
- (void)setTitle:(NSString *)theTitle;
- (NSString *)title;
- (void)setVersion:(NSString *)theVersion;
- (NSString *)version;
- (void)startVideo;
- (void)loadSD;
- (void)shouldLoadFlash;
- (void)loadFlash;
@end

View File

@ -0,0 +1,547 @@
//
// MGMVideoFinder.m
// YouView
//
// Created by Mr. Gecko on 8/3/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMVideoFinder.h"
#import "MGMController.h"
#import "MGMAddons.h"
#import "MGMParentalControls.h"
#import <MGMUsers/MGMUsers.h>
#import <GeckoReporter/GeckoReporter.h>
NSString * const MGMVLVideoURLKey = @"videoURL";
NSString * const MGMVLAudioURLKey = @"audioURL";
NSString * const MGMVLURLKey = @"URL";
NSString * const MGMVLTitle = @"title";
NSString * const MGMVLVersion = @"version";
NSString * const MGMULType = @"type";
NSString * const MGMULTag = @"itag";
NSString * const MGMULURL = @"url";
NSString * const MGMVTType = @"type";
NSString * const MGMVTQuality = @"quality";
NSString * const MGMVTAudio = @"audio";
NSString * const MGMVTVideo = @"video";
NSString * const MGMVT3D = @"3D";
@implementation MGMVideoFinder
- (id)initWithURL:(NSURL *)theURL connectionManager:(MGMURLConnectionManager *)theConnectionManager maxQuality:(int)theMaxQuality delegate:(id)theDelegate {
if (self = [super init]) {
if (theURL==nil || theDelegate==nil) {
[self release];
self = nil;
} else {
maxQuality = theMaxQuality;
requestingSD = NO;
videoURLS = [NSMutableArray new];
URL = [theURL retain];
delegate = theDelegate;
if (theConnectionManager!=nil) {
connectionManager = [theConnectionManager retain];
} else {
connectionManager = [[MGMURLConnectionManager manager] retain];
[connectionManager setUserAgent:MGMUserAgent];
}
#if youviewdebug
NSLog(@"Finding video for %@", theURL);
#endif
NSURLRequest *theRequest = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:theRequest delegate:self];
[connectionManager addHandler:handler];
videoQualities = [NSMutableDictionary new];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"3GP", MGMVTType, @"144p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"13"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"3GP", MGMVTType, @"144p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"17"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"3GP", MGMVTType, @"240p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"36"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"FLV", MGMVTType, @"240p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"5"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"FLV", MGMVTType, @"270p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"6"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"FLV", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"34"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"FLV", MGMVTType, @"480p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"35"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"480p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"18"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"720p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"22"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"1080p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"37"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"2160p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"38"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"144p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"160"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"240p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"133"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"134"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"480p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"135"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"720p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"136"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"1080p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"137"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"1440p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"264"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"2160p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"138"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"M4A", MGMVTType, @"48Kbps", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:NO], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"139"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"M4A", MGMVTType, @"128kbps", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:NO], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"140"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"M4A", MGMVTType, @"256kbps", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:NO], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"141"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"128kbps", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:NO], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"171"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"192kbps", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:NO], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"172"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"240p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"83"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"82"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"520p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"85"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"MP4", MGMVTType, @"720p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"84"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"43"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"480p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"44"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"720p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"45"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"1080p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"46"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"240p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"242"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"243"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"480p 64kbps", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"244"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"480p 110kbps", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"245"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"480p 210kbps", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"246"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"720p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"247"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"1080p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"248"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"1440p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"271"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"2160p", MGMVTQuality, [NSNumber numberWithBool:NO], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:NO], MGMVT3D, nil] forKey:@"272"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"100"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"360p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"101"];
[videoQualities setObject:[NSDictionary dictionaryWithObjectsAndKeys:@"WEBM", MGMVTType, @"720p", MGMVTQuality, [NSNumber numberWithBool:YES], MGMVTAudio, [NSNumber numberWithBool:YES], MGMVTVideo, [NSNumber numberWithBool:YES], MGMVT3D, nil] forKey:@"102"];
}
}
return self;
}
- (void)dealloc {
[URL release];
[connectionManager cancelAll];
[connectionManager release];
[videoURLS release];
[videoQualities release];
[title release];
[version release];
[super dealloc];
}
- (void)processURLs:(NSArray *)urls {
for (int i=0; i<[urls count]; i++) {
NSString *type = [[urls objectAtIndex:i] URLParameterWithName:MGMULType];
NSString *itag = [[urls objectAtIndex:i] URLParameterWithName:MGMULTag];
NSString *videoURL = [[urls objectAtIndex:i] URLParameterWithName:MGMULURL];
NSString *signature = [[urls objectAtIndex:i] URLParameterWithName:@"sig"];
if (signature==nil)
signature = [[urls objectAtIndex:i] URLParameterWithName:@"s"];
if (signature==nil)
signature = [videoURL URLParameterWithName:@"signature"];
if ([signature length]==86) {
NSMutableString *newSignature = [NSMutableString string];
NSArray *signatureBreakDown = [signature componentsSeparatedByString:@"."];
if ([signatureBreakDown count]>=2 && [[signatureBreakDown objectAtIndex:0] length]==42 && [[signatureBreakDown objectAtIndex:1] length]==43) {
[newSignature appendFormat:@"%@.", [[signatureBreakDown objectAtIndex:0] substringFromIndex:2]];
[newSignature appendString:[[signatureBreakDown objectAtIndex:1] substringToIndex:20]];
[newSignature appendString:[[signatureBreakDown objectAtIndex:1] substringWithRange:NSMakeRange(39, 1)]];
[newSignature appendString:[[signatureBreakDown objectAtIndex:1] substringWithRange:NSMakeRange(21, 18)]];
[newSignature appendString:[[signatureBreakDown objectAtIndex:1] substringWithRange:NSMakeRange(20, 1)]];
} else if ([signatureBreakDown count]>=2 && [[signatureBreakDown objectAtIndex:0] length]==43 && [[signatureBreakDown objectAtIndex:1] length]==42) {
[newSignature appendFormat:@"%@.", [[signatureBreakDown objectAtIndex:0] substringFromIndex:3]];
[newSignature appendString:[[signatureBreakDown objectAtIndex:1] substringToIndex:[[signatureBreakDown objectAtIndex:1] length]-2]];
}
if ([newSignature length]!=0) {
signature = newSignature;
}
}
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&signature=%@", videoURL, signature]];
[videoURLS addObject:[NSDictionary dictionaryWithObjectsAndKeys:type, MGMULType, itag, MGMULTag, url, MGMULURL, nil]];
}
}
- (void)handler:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)theError {
[connectionManager release];
connectionManager = nil;
NSLog(@"Error Getting Video: %@", theError);
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert addButtonWithTitle:@"Ok"];
[theAlert setMessageText:@"Error while finding video"];
[theAlert setInformativeText:[theError localizedDescription]];
[theAlert setAlertStyle:2];
[theAlert runModal];
}
- (void)handlerDidFinish:(MGMURLBasicHandler *)theHandler {
NSString *receivedString = [theHandler string];
//NSLog(@"%@", theHandler);
//NSLog(@"%@", receivedString);
if (![[[theHandler response] MIMEType] containsString:@"text/html"]) {
NSLog(@"Hello from special loader.");
NSString *urlMap = nil;
NSRange range = [receivedString rangeOfString:@"url_encoded_fmt_stream_map\": \""];
if (range.location!=NSNotFound) {
NSString *s = [receivedString substringFromIndex:range.location + range.length];
range = [s rangeOfString:@"\""];
if (range.location!=NSNotFound)
urlMap = [s substringFromIndex:range.location + range.length];
}
if (urlMap==nil) {
NSRange range = [receivedString rangeOfString:@"url_encoded_fmt_stream_map': '"];
if (range.location!=NSNotFound) {
NSString *s = [receivedString substringFromIndex:range.location + range.length];
range = [s rangeOfString:@"'"];
if (range.location!=NSNotFound)
urlMap = [s substringFromIndex:range.location + range.length];
}
}
if (urlMap==nil) {
NSDictionary *parameters = [receivedString URLParameters];
NSArray *keys = [parameters allKeys];
for (int i=0; i<[keys count]; i++) {
if ([[keys objectAtIndex:i] containsString:@"url_encoded_fmt_stream_map"]) {
urlMap = [parameters objectForKey:[keys objectAtIndex:i]];
}
}
}
NSString *adaptiveMap = nil;
range = [receivedString rangeOfString:@"adaptive_fmts\": \""];
if (range.location!=NSNotFound) {
NSString *s = [receivedString substringFromIndex:range.location + range.length];
range = [s rangeOfString:@"\""];
if (range.location!=NSNotFound)
adaptiveMap = [s substringFromIndex:range.location + range.length];
}
if (adaptiveMap==nil) {
NSRange range = [receivedString rangeOfString:@"adaptive_fmts': '"];
if (range.location!=NSNotFound) {
NSString *s = [receivedString substringFromIndex:range.location + range.length];
range = [s rangeOfString:@"'"];
if (range.location!=NSNotFound)
adaptiveMap = [s substringFromIndex:range.location + range.length];
}
}
if (adaptiveMap==nil) {
NSDictionary *parameters = [receivedString URLParameters];
NSArray *keys = [parameters allKeys];
for (int i=0; i<[keys count]; i++) {
if ([[keys objectAtIndex:i] containsString:@"adaptive_fmts"]) {
adaptiveMap = [parameters objectForKey:[keys objectAtIndex:i]];
}
}
}
if (urlMap!=nil) {
NSArray *urls = [urlMap componentsSeparatedByString:@","];
[self processURLs:urls];
NSArray *adaptiveURLs = [adaptiveMap componentsSeparatedByString:@","];
[self processURLs:adaptiveURLs];
} else {
NSLog(@"Unable to find url map.");
}
#if youviewdebug
NSLog(@"%@", videoURLS);
#endif
[self startVideo];
} else if (![receivedString containsString:@"verify-age"]) {
NSRange range = NSMakeRange(0, [receivedString length]);
id config = nil;
NSAutoreleasePool *pool = [NSAutoreleasePool new];
while (range.length>1) {
NSRange configRange = [receivedString rangeOfString:@"ytplayer.config = " options:NSCaseInsensitiveSearch range:range];
if (configRange.location!=NSNotFound) {
range.location = configRange.location+configRange.length;
range.length = [receivedString length]-range.location;
NSRange endRange = [receivedString rangeOfString:@"};" options:NSCaseInsensitiveSearch range:range];
if (endRange.location==NSNotFound)
break;
NSString *configString = [receivedString substringWithRange:NSMakeRange(range.location, (endRange.location+endRange.length)-range.location)];
range.location = endRange.location+endRange.length;
range.length = [receivedString length]-range.location;
[config release];
config = [[configString parseJSON] retain];
//NSLog(@"%@", config);
if (config!=nil && [config isKindOfClass:[NSDictionary class]]) {
if ([config objectForKey:@"args"]!=nil) {
break;
}
} else {
[config release];
config = nil;
}
} else {
break;
}
[pool drain];
pool = [NSAutoreleasePool new];
}
[pool drain];
/*if (config==nil) {
NSRange range = NSMakeRange(0, [receivedString length]);
NSAutoreleasePool *pool = [NSAutoreleasePool new];
while (range.length>1) {
NSRange configRange = [receivedString rangeOfString:@"ytplayer.config = " options:NSCaseInsensitiveSearch range:range];
if (configRange.location!=NSNotFound) {
range.location = configRange.location+configRange.length;
range.length = [receivedString length]-range.location;
NSRange endRange = [receivedString rangeOfString:@"};" options:NSCaseInsensitiveSearch range:range];
if (endRange.location==NSNotFound)
break;
NSString *configString = [receivedString substringWithRange:NSMakeRange(range.location, (endRange.location+endRange.length)-range.location)];
range.location = endRange.location+endRange.length;
range.length = [receivedString length]-range.location;
[config release];
config = [[configString parseJSON] retain];
//NSLog(@"%@", config);
if (config!=nil && [config isKindOfClass:[NSDictionary class]]) {
if ([config objectForKey:@"args"]!=nil) {
break;
}
} else {
[config release];
config = nil;
}
} else {
break;
}
[pool drain];
pool = [NSAutoreleasePool new];
}
[pool drain];
}*/
[config autorelease];
NSString *urlMap = nil;
NSString *adaptiveMap = nil;
if (config!=nil && [config isKindOfClass:[NSDictionary class]]) {
//NSLog(@"%@", config);
id tmp = [config objectForKey:@"args"];
if ([tmp isKindOfClass:[NSDictionary class]]) {
urlMap = [tmp objectForKey:@"url_encoded_fmt_stream_map"];
adaptiveMap = [tmp objectForKey:@"adaptive_fmts"];
}
if (urlMap==nil)
NSLog(@"%@", config);
} else {
NSLog(@"What happened here? %@", config);
}
if (urlMap!=nil) {
NSArray *urls = [urlMap componentsSeparatedByString:@","];
[self processURLs:urls];
NSArray *adaptiveURLs = [adaptiveMap componentsSeparatedByString:@","];
[self processURLs:adaptiveURLs];
}
#if youviewdebug
NSLog(@"%@", videoURLS);
#endif
if (title==nil || [title isEqual:@""]) {
NSString *thisTitle = @"";
range = [receivedString rangeOfString:@"<title>"];
if (range.location!=NSNotFound) {
NSString *s = [receivedString substringFromIndex:range.location + range.length];
range = [s rangeOfString:@"</title>"];
if (range.location == NSNotFound) NSLog(@"failed");
thisTitle = [s substringWithRange:NSMakeRange(0, range.location)];
range = [thisTitle rangeOfString:@"-"];
if (range.location!=NSNotFound) {
thisTitle = [thisTitle substringToIndex:range.location];
}
thisTitle = [[thisTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] flattenHTML];
#if youviewdebug
NSLog(@"Found Title: %@", thisTitle);
#endif
}
[self setTitle:thisTitle];
}
if (urlMap==nil) {
NSDictionary *parameters = [[URL query] URLParameters];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://www.youtube.com/get_video_info?video_id=%@&asv=3&el=detailpage&hl=en_US&sts=16136", [parameters objectForKey:@"v"]]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:theRequest delegate:self];
[connectionManager addHandler:handler];
} else {
[self startVideo];
}
} else {
if ([[MGMParentalControls standardParentalControls] boolForKey:MGMAllowFlaggedVideos]) {
NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.youtube.com/verify_age"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
[postRequest setHTTPMethod:@"POST"];
[postRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"];
[postRequest setHTTPBody:[[NSString stringWithFormat:@"next_url=%@?%@&action_confirm=Confirm%20Birth%20Date", [URL path], [URL query]] dataUsingEncoding:NSASCIIStringEncoding]];
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:postRequest delegate:self];
[connectionManager addHandler:handler];
} else {
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert addButtonWithTitle:@"OK"];
[theAlert setMessageText:@"Parental Controls"];
[theAlert setInformativeText:@"You cannot view this video because it is flagged.\nTo enable watching flagged videos, go to YouView->Parental Controls."];
[theAlert runModal];
[connectionManager release];
connectionManager = nil;
}
}
}
- (void)setTitle:(NSString *)theTitle {
[title release];
title = [theTitle retain];
}
- (NSString *)title {
return title;
}
- (void)setVersion:(NSString *)theVersion {
[version release];
version = [theVersion retain];
}
- (NSString *)version {
return version;
}
- (void)startVideo {
//NSLog(@"%@", videoQualities);
int videoQualityFound = 0;
NSDictionary *video = nil;
//int audioQualityFound = 0;
NSDictionary *audio = nil;
for (int i=0; i<[videoURLS count]; i++) {
NSDictionary *videoURL = [videoURLS objectAtIndex:i];
NSDictionary *videoQuality = [videoQualities objectForKey:[videoURL objectForKey:MGMULTag]];
NSLog(@"%@ %@ %@", [videoURL objectForKey:MGMULTag], [videoURL objectForKey:MGMULURL], videoQuality);
if (videoQuality==nil) {
NSLog(@"Unknown Video Quality %@", videoURL);
continue;
}
/*if (audioQualityFound<3 && ![[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"M4A"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"256kbps"]) {
audioQualityFound = 3;
audio = videoURL;
} else if (audioQualityFound<2 && ![[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"M4A"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"192kbps"]) {
audioQualityFound = 2;
audio = videoURL;
} else if (audioQualityFound<1 && ![[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"M4A"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"128kbps"]) {
audioQualityFound = 1;
audio = videoURL;
} else if (audioQualityFound<=0 && ![[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"M4A"]) {
audio = videoURL;
}*/
if (videoQualityFound<5 && maxQuality>=3 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"MP4"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"2160p"]) {
videoQualityFound = 5;
video = videoURL;
[self setVersion:[videoQuality objectForKey:MGMVTType]];
} else if (videoQualityFound<4 && maxQuality>=3 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"MP4"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"1440p"]) {
videoQualityFound = 4;
video = videoURL;
[self setVersion:[videoQuality objectForKey:MGMVTType]];
} else if (videoQualityFound<3 && maxQuality>=2 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"MP4"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"1080p"]) {
videoQualityFound = 3;
video = videoURL;
[self setVersion:[videoQuality objectForKey:MGMVTType]];
} else if (videoQualityFound<2 && maxQuality>=1 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"MP4"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"720p"]) {
videoQualityFound = 2;
video = videoURL;
[self setVersion:[videoQuality objectForKey:MGMVTType]];
} else if (videoQualityFound<1 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"MP4"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"480p"]) {
videoQualityFound = 1;
video = videoURL;
[self setVersion:[videoQuality objectForKey:MGMVTType]];
} else if (videoQualityFound<=0 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"MP4"]) {
video = videoURL;
[self setVersion:[videoQuality objectForKey:MGMVTType]];
}
}
if ([videoURLS count]>0 && video==nil) {
[self shouldLoadFlash];
return;
}
#if youviewdebug
NSLog(@"Using video %@ with %@", [[videoQualities objectForKey:[video objectForKey:MGMULTag]] objectForKey:MGMVTQuality], video);
if (audio!=nil)
NSLog(@"Using audio %@ with %@", [[videoQualities objectForKey:[audio objectForKey:MGMULTag]] objectForKey:MGMVTQuality], audio);
#endif
if (video==nil) {
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert addButtonWithTitle:@"OK"];
[theAlert setMessageText:@"Video"];
[theAlert setInformativeText:@"YouView tried as much as possible and couldn't find the video.\nPlease contact support via the help menu."];
[theAlert runModal];
} else {
NSMutableDictionary *info = [NSMutableDictionary dictionary];
if (![[MGMSystemInfo info] isAfterSnowLeopard]) {
[info setObject:[NSURL URLWithString:[[[video objectForKey:MGMULURL] absoluteString] replace:@"https://" with:@"http://"]] forKey:MGMVLVideoURLKey];
} else {
[info setObject:[video objectForKey:MGMULURL] forKey:MGMVLVideoURLKey];
}
if (![[[videoQualities objectForKey:[video objectForKey:MGMULTag]] objectForKey:MGMVTAudio] boolValue]) {
[info setObject:[audio objectForKey:MGMULURL] forKey:MGMVLAudioURLKey];
}
[info setObject:URL forKey:MGMVLURLKey];
[info setObject:title forKey:MGMVLTitle];
[info setObject:version forKey:MGMVLVersion];
#if youviewdebug
NSLog(@"Passing %@ to load", info);
#endif
[delegate loadVideo:info];
}
}
- (void)loadSD {
#if youviewdebug
NSLog(@"Finding SD version.");
#endif
requestingSD = YES;
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:MGMYTSDURL, [URL URLParameterWithName:@"v"]]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
MGMURLBasicHandler *handlers = [MGMURLBasicHandler handlerWithRequest:theRequest delegate:self];
[connectionManager addHandler:handlers];
}
- (void)shouldLoadFlash {
if (requestingSD) {
NSMutableDictionary *info = [NSMutableDictionary dictionary];
[info setObject:URL forKey:MGMVLURLKey];
[info setObject:title forKey:MGMVLTitle];
[delegate loadFlash:info];
} else {
[self loadSD];
}
}
- (void)loadFlash {
#if youviewdebug
NSLog(@"Loading flash version.");
#endif
int qualityFound = 0;
NSDictionary *video = nil;
for (int i=0; i<[videoURLS count]; i++) {
NSDictionary *videoURL = [videoURLS objectAtIndex:i];
NSDictionary *videoQuality = [videoQualities objectForKey:[videoURL objectForKey:MGMULTag]];
if (videoQuality==nil) {
NSLog(@"Unknown Video Quality %@", [videoURL objectForKey:MGMULTag]);
continue;
}
if (qualityFound<3 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"FLV"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"480p"]) {
qualityFound = 3;
video = videoURL;
} else if (qualityFound<2 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"FLV"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"360p"]) {
qualityFound = 2;
video = videoURL;
} else if (qualityFound<1 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"FLV"] && [[videoQuality objectForKey:MGMVTQuality] containsString:@"270p"]) {
qualityFound = 1;
video = videoURL;
} else if (qualityFound<=0 && ![[videoQuality objectForKey:MGMVT3D] boolValue] && [[videoQuality objectForKey:MGMVTVideo] boolValue] && [[videoQuality objectForKey:MGMVTAudio] boolValue] && [[videoQuality objectForKey:MGMVTType] isEqual:@"FLV"]) {
video = videoURL;
}
}
#if youviewdebug
NSLog(@"Should load video %@ with URL %@.", [[videoQualities objectForKey:[video objectForKey:MGMULTag]] objectForKey:MGMVTQuality], video);
#endif
if (video==nil) {
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert addButtonWithTitle:@"OK"];
[theAlert setMessageText:@"Video"];
[theAlert setInformativeText:@"YouView tried as much as possible and couldn't find the video.\nPlease contact support via the help menu."];
[theAlert runModal];
} else {
NSMutableDictionary *info = [NSMutableDictionary dictionary];
[info setObject:[video objectForKey:MGMULURL] forKey:MGMVLVideoURLKey];
[info setObject:URL forKey:MGMVLURLKey];
[info setObject:title forKey:MGMVLTitle];
[info setObject:version forKey:MGMVLVersion];
[delegate loadVideo:info];
}
}
@end

View File

@ -0,0 +1,27 @@
//
// MGMYVToolConnection.h
// YouView
//
// Created by Mr. Gecko on 5/28/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <Security/Authorization.h>
#import <Security/AuthorizationTags.h>
@protocol MGMYVToolProtocol;
@class MGMAdminAction;
@interface MGMYVToolConnection : NSObject {
MGMAdminAction *adminAction;
id yvTool;
NSConnection *yvToolConnection;
}
+ (id)connectionWithAuthorization:(AuthorizationRef)theAuthorization;
- (id)initWithAuthorization:(AuthorizationRef)theAuthorization;
- (void)connectToServer;
- (void)disconnectFromServer;
- (BOOL)isServerConnected;
- (id<MGMYVToolProtocol>)server;
@end

View File

@ -0,0 +1,77 @@
//
// MGMYVToolConnection.m
// YouView
//
// Created by Mr. Gecko on 5/28/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMYVToolConnection.h"
#import "MGMYVToolProtocol.h"
#import "MGMAdminAction.h"
@implementation MGMYVToolConnection
+ (id)connectionWithAuthorization:(AuthorizationRef)theAuthorization {
return [[[self alloc] initWithAuthorization:theAuthorization] autorelease];
}
- (id)initWithAuthorization:(AuthorizationRef)theAuthorization {
if (self = [super init]) {
adminAction = [MGMAdminAction new];
if (theAuthorization!=NULL)
[adminAction setAuthorization:theAuthorization];
[adminAction launchCommand:[[NSBundle mainBundle] pathForResource:@"YVTool" ofType:@""] withArguments:[NSArray arrayWithObject:[NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]]];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
[self connectToServer];
}
return self;
}
- (void)dealloc {
#if releaseDebug
NSLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
[self disconnectFromServer];
[adminAction release];
[yvToolConnection release];
[super dealloc];
}
- (void)connectToServer {
[yvToolConnection release];
yvToolConnection = [[NSConnection connectionWithRegisteredName:@"MGMYVServer" host:nil] retain];
if (yvToolConnection==nil) {
NSLog(@"Couldn't connect to YVTool server.");
return;
}
[yvTool release];
yvTool = [[yvToolConnection rootProxy] retain];
if (yvTool==nil) {
NSLog(@"Couldn't set proxy with YVTool server.");
[yvToolConnection release];
yvToolConnection = nil;
return;
}
[yvTool setProtocolForProxy:@protocol(MGMYVToolProtocol)];
}
- (void)disconnectFromServer {
@try {
[yvTool quit];
[yvTool release];
yvTool = nil;
[yvToolConnection release];
yvToolConnection = nil;
}
@catch (NSException * e) {
NSLog(@"Couldn't disconnect.");
}
}
- (BOOL)isServerConnected {
return (yvToolConnection!=nil);
}
- (id<MGMYVToolProtocol>)server {
if (![self isServerConnected]) {
[self connectToServer];
}
return yvTool;
}
@end

View File

@ -0,0 +1,16 @@
//
// MGMYVToolProtocol.h
// YouView
//
// Created by Mr. Gecko on 5/28/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@protocol MGMYVToolProtocol
- (void)changePremissionsForPath:(NSString *)thePath to:(NSString *)thePermissions;
- (void)changeOwnerForPath:(NSString *)thePath to:(NSString *)theOwner;
- (void)quit;
@end

View File

@ -0,0 +1,193 @@
//
// MGMPlayer.h
// YouView
//
// Created by Mr. Gecko on 10/15/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <QTKit/QTKit.h>
extern NSString * const MGMILObject;
extern NSString * const MGMILURL;
extern NSString * const MGMILID;
extern NSString * const MGMILPath;
@class MGMBackgroundView, MGMURLConnectionManager, MGMVideoFinder, QTMovieView, QTMovie, MGMController, MGMPlayerTracking, MGMPlayerControls;
@interface MGMPlayer : NSObject {
BOOL player;
IBOutlet NSWindow *mainWindow;
IBOutlet MGMBackgroundView *mainView;
IBOutlet NSWindow *fullScreenWindow;
IBOutlet MGMBackgroundView *fullScreenView;
IBOutlet MGMPlayerControls *controlsView;
IBOutlet NSWindow *controlsWindow;
IBOutlet NSView *browserView;
IBOutlet NSView *movieView;
MGMController *controller;
//Essentials
NSMutableDictionary *currentQuery;
NSString *nextPageToken;
NSString *prevPageToken;
NSArray *resultsArray;
IBOutlet NSTableView *resultsTable;
IBOutlet NSSearchField *searchBox;
IBOutlet NSProgressIndicator *progressIndecator;
IBOutlet NSSegmentedControl *nextPrevious;
IBOutlet NSTextField *foundResults;
IBOutlet NSTextField *page;
NSLock *loaderLock;
MGMURLConnectionManager *connectionManager;
MGMURLConnectionManager *imageLoaderManager;
int totalResults;
int start;
int resultsCount;
NSString *query;
IBOutlet NSButton *loginButton;
//Message
NSTimer *messageTimer;
NSMutableArray *messages;
IBOutlet NSTextField *messageField;
//Order
IBOutlet NSMenuItem *relevance;
IBOutlet NSMenuItem *published;
IBOutlet NSMenuItem *viewCount;
IBOutlet NSMenuItem *rating;
//Movie View
NSURL *entry;
NSString *title;
MGMVideoFinder *videoFinder;
IBOutlet QTMovieView *moviePlayer;
IBOutlet MGMPlayerTracking *PlayerTracking;
BOOL FullScreen;
BOOL resized;
NSRect windowFrame;
NSRect windowContentFrame;
BOOL movieOpen;
BOOL moviePlaying;
BOOL transitioning;
NSTimer *updateControlsTimer;
}
+ (id)playerWithVideo:(NSURL *)theVideo controller:(MGMController *)theController player:(BOOL)isPlayer;
- (id)initWithVideo:(NSURL *)theVideo controller:(MGMController *)theController player:(BOOL)isPlayer;
- (NSWindow *)mainWindow;
- (NSWindow *)fullScreenWindow;
- (NSWindow *)controlsWindow;
- (MGMPlayerControls *)controlsView;
- (MGMPlayerTracking *)playerTracking;
- (QTMovieView *)moviePlayer;
- (void)setResults:(NSArray *)theResults;
- (NSArray *)results;
- (int)resultsCount;
- (NSTableView *)resultsTable;
- (int)totalResults;
- (int)start;
- (BOOL)player;
- (BOOL)isMovieOpen;
- (BOOL)isMoviePlaying;
- (BOOL)isFullScreen;
- (NSURL *)entry;
- (NSString *)title;
- (void)startProgress;
- (void)stopProgress;
- (void)startImageLoader;
- (void)reloadRecentSearches;
- (IBAction)clearRecentSearches:(id)sender;
- (IBAction)setOrderBy:(id)sender;
- (void)reloadData;
- (void)search;
- (IBAction)nextPrevious:(id)sender;
- (void)addMessage:(NSString *)message;
- (void)messageTimer;
- (void)removeAllMessages;
- (IBAction)openVideo:(id)sender;
- (IBAction)openVideoReverse:(id)sender;
- (void)openMovie:(NSURL *)theVideo;
- (void)closeMovie;
- (void)loop;
- (void)goFullScreen;
- (void)updateControls;
- (void)controlWithKeyEvent:(NSEvent *)theEvent;
- (void)setTitle;
@end
@interface MGMFullScreenWindow : NSWindow {
IBOutlet MGMPlayer *player;
}
@end
@interface MGMResultsTable : NSTableView {
IBOutlet MGMPlayer *player;
}
@end
@interface MGMBottomControl : NSView {
}
@end
@interface MGMPlayerTracking : NSView {
IBOutlet MGMPlayer *player;
NSTrackingRectTag rolloverTrackingRectTag;
NSTimer *hideCursorTimer;
BOOL wasAcceptingMouseEvents;
BOOL fadeIn;
NSTimer *fadeTimer;
BOOL controls;
BOOL playerEntered;
NSTimer *controlsTimer;
}
- (void)releaseTimers;
- (void)resetTracking;
- (void)hideCursorNow;
- (void)controlsEntered;
- (void)controlsExited;
@end
@interface QTMovie (MGMAdditions)
- (QTTime)maxTimeLoaded;
- (NSArray *)loadedRanges;
- (long)loadState;
@end
@interface MGMPlayerControls : NSView {
IBOutlet MGMPlayer *player;
NSTrackingRectTag rolloverTrackingRectTag;
BOOL wasAcceptingMouseEvents;
//Controls
NSRect VCMuteR;
NSRect VCPlayR;
NSRect durationR;
NSRect currentTimeR;
NSRect VCFullScreenR;
NSRect VCSizeR;
NSRect VCPositionR;
NSRect VCBarRect;
BOOL inBar;
BOOL resizing;
float lastVolume;
}
- (void)resetTracking;
@end
@interface MGMControlsWindow : NSWindow {
IBOutlet MGMPlayerControls *playerControls;
}
@end
@interface MGMBackgroundView : NSView {
NSColor *backgroundColor;
}
- (void)setBackgroundColor:(NSColor *)theColor;
- (NSColor *)backgroundColor;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
//
// MGMResult.h
// YouView
//
// Created by Mr. Gecko on 4/25/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MGMResult : NSObject {
NSDictionary *item;
IBOutlet NSView *mainView;
IBOutlet NSImageView *previewView;
IBOutlet NSTextField *titleField;
IBOutlet NSTextField *descriptionField;
IBOutlet NSTextField *authorField;
IBOutlet NSTextField *addedField;
}
+ (id)resultWithItem:(NSDictionary *)video;
- (id)initWithItem:(NSDictionary *)video;
- (NSView *)view;
- (NSURL *)entry;
- (NSDictionary *)item;
- (void)loadImage;
- (void)setImage:(NSImage *)image;
- (NSImage *)image;
@end

View File

@ -0,0 +1,101 @@
//
// MGMResult.m
// YouView
//
// Created by Mr. Gecko on 4/25/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMResult.h"
#import "MGMAddons.h"
#import "MGMController.h"
#import <MGMUsers/MGMUsers.h>
#import <GeckoReporter/GeckoReporter.h>
@implementation MGMResult
+ (id)resultWithItem:(NSDictionary *)video {
return [[[self alloc] initWithItem:video] autorelease];
}
- (id)initWithItem:(NSDictionary *)video {
if (self = [super init]) {
if (![NSBundle loadNibNamed:@"MGMResultView" owner:self]) {
[self release];
self = nil;
} else {
NSLog(@"%@", video);
item = [video retain];
[self loadImage];
NSDictionary *snippet = [item objectForKey:@"snippet"];
[titleField setStringValue:[snippet objectForKey:@"title"]];
[descriptionField setStringValue:[snippet objectForKey:@"description"]];
NSString *author = [snippet objectForKey:@"channelTitle"];
if ([author isEqual:@""]) {
author = [snippet objectForKey:@"channelId"];
}
[authorField setStringValue:author];
NSString *published = [snippet objectForKey:@"publishedAt"];
NSRange dotRange = [published rangeOfString:@"."];
if (dotRange.location!=NSNotFound) {
published = [published substringToIndex:dotRange.location];
}
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];//2015-03-14T01:45:20.000Z
NSDate *date = [formatter dateFromString:published];
[formatter setTimeZone:[NSTimeZone localTimeZone]];
[formatter setDateFormat:@"M/dd/yy hh:mm:ss a"];
NSString *formattedDate = [formatter stringFromDate:date];
if (formattedDate!=nil)
[addedField setStringValue:formattedDate];
}
}
return self;
}
- (void)dealloc {
#if releaseDebug
MGMLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
[item release];
[mainView removeFromSuperview];
[mainView release];
[super dealloc];
}
- (NSView *)view {
return mainView;
}
- (NSString *)accessibilityRole {
return @"video";
}
- (NSString *)accessibilityDescription {
return @"";
}
- (NSDictionary *)item {
return item;
}
- (NSURL *)entry {
return [NSURL URLWithString:[NSString stringWithFormat:@"http://www.youtube.com/watch?v=%@", [[item objectForKey:@"id"] objectForKey:@"videoId"]]];
}
- (void)loadImage {
NSString *imagePath = [[[MGMUser cachePath] stringByAppendingPathComponent:[[item objectForKey:@"id"] objectForKey:@"videoId"]] stringByAppendingPathExtension:@"tiff"];
if ([[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {
[self setImage:[[[NSImage alloc] initWithContentsOfFile:imagePath] autorelease]];
}
}
- (void)setImage:(NSImage *)image {
[previewView setImage:image];
[previewView setHidden:NO];
if ([[NSUserDefaults standardUserDefaults] boolForKey:MGMAnimations]) {
NSMutableDictionary *animationInfo = [NSMutableDictionary dictionary];
[animationInfo setObject:previewView forKey:NSViewAnimationTargetKey];
[animationInfo setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
NSViewAnimation *animation = [[[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:animationInfo]] autorelease];
[animation setDuration:1.0];
[animation startAnimation];
}
}
- (NSImage *)image {
return [previewView image];
}
@end

View File

@ -0,0 +1,28 @@
//
// MGMDonatePane.h
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
extern NSString * const MGMDSalt1;
extern NSString * const MGMDSalt2;
extern NSString * const MGMDonationPath;
extern NSString * const MGMDKey;
extern NSString * const MGMDHash;
extern NSString * const MGMDName;
extern NSString * const MGMDStatus;
@interface MGMDonatePane : MGMPreferencesPane {
IBOutlet NSView *mainView;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (IBAction)donate:(id)sender;
@end

View File

@ -0,0 +1,52 @@
//
// MGMDonatePane.m
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMDonatePane.h"
#import "MGMController.h"
NSString * const MGMDSalt1 = @"lll3jh653k";
NSString * const MGMDSalt2 = @"jgsllwi32l5";
NSString * const MGMDonationPath = @".info.plist";
NSString * const MGMDKey = @"key";
NSString * const MGMDHash = @"hash";
NSString * const MGMDName = @"name";
NSString * const MGMDStatus = @"status";
@implementation MGMDonatePane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"DonatePane" owner:self]) {
NSLog(@"Unable to load Nib for Donate Preferences");
[self release];
self = nil;
} else {
}
}
return self;
}
- (void)dealloc {
[mainView release];
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"Donate"]];
}
+ (NSString *)title {
return @"Donate";
}
- (NSView *)preferencesView {
return mainView;
}
- (IBAction)donate:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://mrgeckosmedia.com/donate?purpose=youview"]];
}
@end

View File

@ -0,0 +1,31 @@
//
// MGMGeneralPane.h
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
@interface MGMGeneralPane : MGMPreferencesPane {
IBOutlet NSView *mainView;
IBOutlet NSMatrix *maxQuality;
IBOutlet NSMatrix *windowMode;
IBOutlet NSButton *animationsButton;
IBOutlet NSButton *FSFloatButton;
IBOutlet NSButton *FSSpacesButton;
IBOutlet NSTextField *pageMax;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (IBAction)saveVideoQuality:(id)sender;
- (IBAction)saveWindowMode:(id)sender;
- (IBAction)saveAnimations:(id)sender;
- (IBAction)saveFSFloat:(id)sender;
- (IBAction)saveFSSpaces:(id)sender;
- (IBAction)save:(id)sender;
@end

View File

@ -0,0 +1,69 @@
//
// MGMGeneralPane.m
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMGeneralPane.h"
#import "MGMController.h"
@implementation MGMGeneralPane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"GeneralPane" owner:self]) {
NSLog(@"Unable to load Nib for General Preferences");
[self release];
self = nil;
} else {
[maxQuality selectCellAtRow:0 column:[preferences integerForKey:MGMMaxQuality]];
[windowMode selectCellAtRow:0 column:[preferences integerForKey:MGMWindowMode]];
[animationsButton setState:([preferences boolForKey:MGMAnimations] ? NSOnState : NSOffState)];
[FSFloatButton setState:([preferences boolForKey:MGMFSFloat] ? NSOnState : NSOffState)];
[FSSpacesButton setState:([preferences boolForKey:MGMFSSpaces] ? NSOnState : NSOffState)];
[pageMax setIntValue:[preferences integerForKey:MGMPageMax]];
}
}
return self;
}
- (void)dealloc {
[mainView release];
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"General"]];
}
+ (NSString *)title {
return @"General";
}
- (NSView *)preferencesView {
return mainView;
}
- (IBAction)saveVideoQuality:(id)sender {
[preferences setInteger:[maxQuality selectedColumn] forKey:MGMMaxQuality];
}
- (IBAction)saveWindowMode:(id)sender {
[preferences setInteger:[windowMode selectedColumn] forKey:MGMWindowMode];
}
- (IBAction)saveAnimations:(id)sender {
[preferences setBool:([animationsButton state]==NSOnState) forKey:MGMAnimations];
}
- (IBAction)saveFSFloat:(id)sender {
[preferences setBool:([FSFloatButton state]==NSOnState) forKey:MGMFSFloat];
[[NSNotificationCenter defaultCenter] postNotificationName:MGMFSSettingsNotification object:nil];
}
- (IBAction)saveFSSpaces:(id)sender {
[preferences setBool:([FSSpacesButton state]==NSOnState) forKey:MGMFSSpaces];
[[NSNotificationCenter defaultCenter] postNotificationName:MGMFSSettingsNotification object:nil];
}
- (IBAction)save:(id)sender {
int max = [pageMax intValue];
if (max<=0)
max = [preferences integerForKey:MGMPageMax];
[pageMax setIntValue:max];
[preferences setInteger:max forKey:MGMPageMax];
}
@end

View File

@ -0,0 +1,28 @@
//
// MGMParentalControlsPane.h
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
@class SFAuthorizationView, MGMYVToolConnection;
@interface MGMParentalControlsPane : MGMPreferencesPane {
IBOutlet NSView *mainView;
IBOutlet NSButton *flaggedVideo;
IBOutlet NSMatrix *safeSearch;
AuthorizationRights rights;
IBOutlet SFAuthorizationView *autherizationView;
MGMYVToolConnection *yvToolConnection;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (IBAction)saveFlaggedVideos:(id)sender;
- (IBAction)saveSafeSearch:(id)sender;
@end

View File

@ -0,0 +1,106 @@
//
// MGMParentalControlsPane.m
// YouView
//
// Created by Mr. Gecko on 7/29/10.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMParentalControlsPane.h"
#import "MGMController.h"
#import "MGMParentalControls.h"
#import "MGMAdminAction.h"
#import "MGMYVToolConnection.h"
#import "MGMYVToolProtocol.h"
#import <SecurityInterface/SFAuthorizationView.h>
@implementation MGMParentalControlsPane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"ParentalControlsPane" owner:self]) {
NSLog(@"Unable to load Nib for General Preferences");
[self release];
self = nil;
} else {
rights = [MGMAdminAction rightsForCommands:[NSArray arrayWithObject:[[NSBundle mainBundle] pathForResource:@"YVTool" ofType:@""]]];
[autherizationView setAuthorizationRights:&rights];
[autherizationView setDelegate:self];
[autherizationView updateStatus:self];
[autherizationView setAutoupdate:YES];
MGMParentalControls *parentalControls = [MGMParentalControls standardParentalControls];
if ([parentalControls boolForKey:MGMAllowFlaggedVideos]) {
[flaggedVideo setState:NSOnState];
} else {
[flaggedVideo setState:NSOffState];
}
NSString *safeSearchValue = [parentalControls stringForKey:MGMSafeSearch];
if (safeSearchValue==nil) {
safeSearchValue = @"moderate";
}
if ([safeSearchValue isEqual:@"none"])
[safeSearch selectCellAtRow:0 column:0];
else if ([safeSearchValue isEqual:@"moderate"])
[safeSearch selectCellAtRow:1 column:0];
else if ([safeSearchValue isEqual:@"strict"])
[safeSearch selectCellAtRow:2 column:0];
[parentalControls setString:safeSearchValue forKey:MGMSafeSearch];
[parentalControls save];
}
}
return self;
}
- (void)dealloc {
[mainView release];
[yvToolConnection release];
free(rights.items);
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"ParentalControls"]];
}
+ (NSString *)title {
return @"Parental Controls";
}
- (NSView *)preferencesView {
return mainView;
}
- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view {
if (yvToolConnection==nil)
yvToolConnection = [[MGMYVToolConnection connectionWithAuthorization:[[autherizationView authorization] authorizationRef]] retain];
[yvToolConnection isServerConnected];
[flaggedVideo setEnabled:YES];
[safeSearch setEnabled:YES];
}
- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view {
[flaggedVideo setEnabled:NO];
[safeSearch setEnabled:NO];
}
- (IBAction)saveFlaggedVideos:(id)sender {
if ([autherizationView authorizationState]==SFAuthorizationViewUnlockedState) {
MGMParentalControls *parentalControls = [MGMParentalControls standardParentalControls];
[[yvToolConnection server] changePremissionsForPath:[parentalControls path] to:@"666"];
[parentalControls setBool:([flaggedVideo state]==NSOnState) forKey:MGMAllowFlaggedVideos];
[[yvToolConnection server] changePremissionsForPath:[parentalControls path] to:@"644"];
[[yvToolConnection server] changeOwnerForPath:[parentalControls path] to:@"root"];
}
}
- (IBAction)saveSafeSearch:(id)sender {
if ([autherizationView authorizationState]==SFAuthorizationViewUnlockedState) {
MGMParentalControls *parentalControls = [MGMParentalControls standardParentalControls];
[[yvToolConnection server] changePremissionsForPath:[parentalControls path] to:@"666"];
NSString *safeSearchValue = @"strict";
if ([safeSearch selectedRow]==0)
safeSearchValue = @"none";
else if ([safeSearch selectedRow]==1)
safeSearchValue = @"moderate";
[parentalControls setString:safeSearchValue forKey:MGMSafeSearch];
[[yvToolConnection server] changePremissionsForPath:[parentalControls path] to:@"644"];
[[yvToolConnection server] changeOwnerForPath:[parentalControls path] to:@"root"];
}
}
@end

View File

@ -0,0 +1,37 @@
/*****************************************************************************
* RemoteControlWrapper.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ÄúAS ISÄù, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import "HIDRemoteControlDevice.h"
/* Interacts with the Apple Remote Control HID device
The class is not thread safe
*/
@interface AppleRemote : HIDRemoteControlDevice {
}
@end

View File

@ -0,0 +1,105 @@
/*****************************************************************************
* RemoteControlWrapper.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "AppleRemote.h"
#import <mach/mach.h>
#import <mach/mach_error.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDKeys.h>
#import <GeckoReporter/MGMSystemInfo.h>
const char* AppleRemoteDeviceName = "AppleIRController";
// the WWDC 07 Leopard Build is missing the constant
#ifndef NSAppKitVersionNumber10_4
#define NSAppKitVersionNumber10_4 824
#endif
@implementation AppleRemote
+ (const char*) remoteControlDeviceName {
return AppleRemoteDeviceName;
}
- (void) setCookieMappingInDictionary: (NSMutableDictionary*) _cookieToButtonMapping {
MGMSystemInfo *sysInfo = [[MGMSystemInfo new] autorelease];
if ([sysInfo isAfterSnowLeopard]) {
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"33_31_30_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"33_32_30_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"33_22_21_20_2_33_22_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"33_23_21_20_2_33_23_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"33_24_21_20_2_33_24_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"33_25_21_20_2_33_25_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"33_21_20_14_12_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"33_21_20_13_12_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"33_21_20_2_33_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Hold] forKey:@"37_33_21_20_2_37_33_21_20_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
} else if ([sysInfo isAfterLeopard]) {
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"31_29_28_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"31_30_28_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"31_20_19_18_31_20_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"31_21_19_18_31_21_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"31_22_19_18_31_22_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"31_23_19_18_31_23_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"31_19_18_4_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"31_19_18_3_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"31_19_18_31_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Hold] forKey:@"35_31_19_18_35_31_19_18_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
} else if ([sysInfo isAfterTiger]) {
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"14_12_11_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"14_13_11_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"14_7_6_14_7_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"14_8_6_14_8_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"14_9_6_14_9_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"14_10_6_14_10_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"14_6_4_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"14_6_3_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"14_6_14_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Hold] forKey:@"18_14_6_18_14_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
}
}
- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
if (pressedDown == NO && event == kRemoteButtonMenu_Hold) {
// There is no seperate event for pressed down on menu hold. We are simulating that event here
[super sendRemoteButtonEvent:event pressedDown:YES];
}
[super sendRemoteButtonEvent:event pressedDown:pressedDown];
if (pressedDown && (event == kRemoteButtonRight || event == kRemoteButtonLeft || event == kRemoteButtonPlay || event == kRemoteButtonMenu || event == kRemoteButtonPlay_Hold)) {
// There is no seperate event when the button is being released. We are simulating that event here
[super sendRemoteButtonEvent:event pressedDown:NO];
}
}
@end

View File

@ -0,0 +1,49 @@
/*****************************************************************************
* GlobalKeyboardDevice.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#import "RemoteControl.h"
/*
This class registers for a number of global keyboard shortcuts to simulate a remote control
*/
@interface GlobalKeyboardDevice : RemoteControl {
NSMutableDictionary* hotKeyRemoteEventMapping;
EventHandlerRef eventHandlerRef;
}
- (void) mapRemoteButton: (RemoteControlEventIdentifier) remoteButtonIdentifier defaultKeycode: (unsigned int) defaultKeycode defaultModifiers: (unsigned int) defaultModifiers;
- (BOOL)registerHotKeyCode: (unsigned int) keycode modifiers: (unsigned int) modifiers remoteEventIdentifier: (RemoteControlEventIdentifier) identifier;
static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon );
@end

View File

@ -0,0 +1,241 @@
/*****************************************************************************
* GlobalKeyboardDevice.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "GlobalKeyboardDevice.h"
#define F1 122
#define F2 120
#define F3 99
#define F4 118
#define F5 96
#define F6 97
#define F7 98
/*
the following default keys are read and shall be used to change the keyboard mapping
mac.remotecontrols.GlobalKeyboardDevice.plus_modifiers
mac.remotecontrols.GlobalKeyboardDevice.plus_keycode
mac.remotecontrols.GlobalKeyboardDevice.minus_modifiers
mac.remotecontrols.GlobalKeyboardDevice.minus_keycode
mac.remotecontrols.GlobalKeyboardDevice.play_modifiers
mac.remotecontrols.GlobalKeyboardDevice.play_keycode
mac.remotecontrols.GlobalKeyboardDevice.left_modifiers
mac.remotecontrols.GlobalKeyboardDevice.left_keycode
mac.remotecontrols.GlobalKeyboardDevice.right_modifiers
mac.remotecontrols.GlobalKeyboardDevice.right_keycode
mac.remotecontrols.GlobalKeyboardDevice.menu_modifiers
mac.remotecontrols.GlobalKeyboardDevice.menu_keycode
mac.remotecontrols.GlobalKeyboardDevice.playhold_modifiers
mac.remotecontrols.GlobalKeyboardDevice.playhold_keycode
*/
@implementation GlobalKeyboardDevice
- (id) initWithDelegate: (id) _remoteControlDelegate {
if (self = [super initWithDelegate: _remoteControlDelegate]) {
hotKeyRemoteEventMapping = [NSMutableDictionary new];
unsigned int modifiers = cmdKey + shiftKey /*+ optionKey*/ + controlKey;
[self mapRemoteButton:kRemoteButtonPlus defaultKeycode:F1 defaultModifiers:modifiers];
[self mapRemoteButton:kRemoteButtonMinus defaultKeycode:F2 defaultModifiers:modifiers];
[self mapRemoteButton:kRemoteButtonPlay defaultKeycode:F3 defaultModifiers:modifiers];
[self mapRemoteButton:kRemoteButtonLeft defaultKeycode:F4 defaultModifiers:modifiers];
[self mapRemoteButton:kRemoteButtonRight defaultKeycode:F5 defaultModifiers:modifiers];
[self mapRemoteButton:kRemoteButtonMenu defaultKeycode:F6 defaultModifiers:modifiers];
[self mapRemoteButton:kRemoteButtonPlay_Hold defaultKeycode:F7 defaultModifiers:modifiers];
}
return self;
}
- (void) dealloc {
[hotKeyRemoteEventMapping release];
[super dealloc];
}
- (void) mapRemoteButton: (RemoteControlEventIdentifier) remoteButtonIdentifier defaultKeycode: (unsigned int) defaultKeycode defaultModifiers: (unsigned int) defaultModifiers {
NSString* defaultsKey = @"unknown";
switch(remoteButtonIdentifier) {
case kRemoteButtonPlus:
defaultsKey = @"plus";
break;
case kRemoteButtonMinus:
defaultsKey = @"minus";
break;
case kRemoteButtonMenu:
defaultsKey = @"menu";
break;
case kRemoteButtonPlay:
defaultsKey = @"play";
break;
case kRemoteButtonRight:
defaultsKey = @"right";
break;
case kRemoteButtonLeft:
defaultsKey = @"left";
break;
case kRemoteButtonPlay_Hold:
defaultsKey = @"playhold";
break;
default:
NSLog(@"Unknown global keyboard defaults key for remote button identifier %d", remoteButtonIdentifier);
}
NSNumber* modifiersCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_modifiers", defaultsKey]];
NSNumber* keycodeCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_keycode", defaultsKey]];
unsigned int modifiers = defaultModifiers;
if (modifiersCfg) modifiers = [modifiersCfg unsignedIntValue];
unsigned int keycode = defaultKeycode;
if (keycodeCfg) keycode = [keycodeCfg unsignedIntValue];
[self registerHotKeyCode: keycode modifiers: modifiers remoteEventIdentifier: remoteButtonIdentifier];
}
- (void) setListeningToRemote: (BOOL) value {
if (value == [self isListeningToRemote]) return;
if (value) {
[self startListening: self];
} else {
[self stopListening: self];
}
}
- (BOOL) isListeningToRemote {
return (eventHandlerRef!=NULL);
}
- (IBAction) startListening: (id) sender {
if (eventHandlerRef) return;
EventTypeSpec eventSpec[2] = {
{ kEventClassKeyboard, kEventHotKeyPressed },
{ kEventClassKeyboard, kEventHotKeyReleased }
};
InstallEventHandler( GetEventDispatcherTarget(),
(EventHandlerProcPtr)hotKeyEventHandler,
2, eventSpec, self, &eventHandlerRef);
}
- (IBAction) stopListening: (id) sender {
RemoveEventHandler(eventHandlerRef);
eventHandlerRef = NULL;
}
- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
NSEnumerator* values = [hotKeyRemoteEventMapping objectEnumerator];
NSNumber* remoteIdentifier;
while( (remoteIdentifier = [values nextObject]) ) {
if ([remoteIdentifier unsignedIntValue] == identifier) return YES;
}
return NO;
}
+ (const char*) remoteControlDeviceName {
return "Keyboard";
}
- (BOOL)registerHotKeyCode: (unsigned int) keycode modifiers: (unsigned int) modifiers remoteEventIdentifier: (RemoteControlEventIdentifier) identifier {
OSStatus err;
EventHotKeyID hotKeyID;
EventHotKeyRef carbonHotKey;
hotKeyID.signature = 'PTHk';
hotKeyID.id = (long)keycode;
err = RegisterEventHotKey(keycode, modifiers, hotKeyID, GetEventDispatcherTarget(), 0, &carbonHotKey );
if( err )
return NO;
[hotKeyRemoteEventMapping setObject: [NSNumber numberWithInt:identifier] forKey: [NSNumber numberWithUnsignedInt: hotKeyID.id]];
return YES;
}
/*
- (void)unregisterHotKey: (PTHotKey*)hotKey
{
OSStatus err;
EventHotKeyRef carbonHotKey;
NSValue* key;
if( [[self allHotKeys] containsObject: hotKey] == NO )
return;
carbonHotKey = [self _carbonHotKeyForHotKey: hotKey];
NSAssert( carbonHotKey != nil, @"" );
err = UnregisterEventHotKey( carbonHotKey );
//Watch as we ignore 'err':
key = [NSValue valueWithPointer: carbonHotKey];
[mHotKeys removeObjectForKey: key];
[self _updateEventHandler];
//See that? Completely ignored
}
*/
- (RemoteControlEventIdentifier) remoteControlEventIdentifierForID: (unsigned int) id {
NSNumber* remoteEventIdentifier = [hotKeyRemoteEventMapping objectForKey:[NSNumber numberWithUnsignedInt: id]];
return [remoteEventIdentifier unsignedIntValue];
}
- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
[delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self];
}
static RemoteControlEventIdentifier lastEvent;
static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* userData )
{
GlobalKeyboardDevice* keyboardDevice = (GlobalKeyboardDevice*) userData;
EventHotKeyID hkCom;
GetEventParameter(inEvent,kEventParamDirectObject,typeEventHotKeyID,NULL,sizeof(hkCom),NULL,&hkCom);
RemoteControlEventIdentifier identifier = [keyboardDevice remoteControlEventIdentifierForID:hkCom.id];
if (identifier == 0) return noErr;
BOOL pressedDown = YES;
if (identifier != lastEvent) {
lastEvent = identifier;
} else {
lastEvent = 0;
pressedDown = NO;
}
[keyboardDevice sendRemoteButtonEvent: identifier pressedDown: pressedDown];
return noErr;
}
@end

View File

@ -0,0 +1,64 @@
/*****************************************************************************
* HIDRemoteControlDevice.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ÄúAS ISÄù, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import <IOKit/hid/IOHIDLib.h>
#import "RemoteControl.h"
/*
Base class for HID based remote control devices
*/
@interface HIDRemoteControlDevice : RemoteControl {
IOHIDDeviceInterface** hidDeviceInterface;
IOHIDQueueInterface** queue;
NSMutableArray* allCookies;
NSMutableDictionary* cookieToButtonMapping;
CFRunLoopSourceRef eventSource;
BOOL fixSecureEventInputBug;
BOOL openInExclusiveMode;
BOOL processesBacklog;
int supportedButtonEvents;
}
// When your application needs to much time on the main thread when processing an event other events
// may already be received which are put on a backlog. As soon as your main thread
// has some spare time this backlog is processed and may flood your delegate with calls.
// Backlog processing is turned off by default.
- (BOOL) processesBacklog;
- (void) setProcessesBacklog: (BOOL) value;
// methods that should be overwritten by subclasses
- (void) setCookieMappingInDictionary: (NSMutableDictionary*) cookieToButtonMapping;
- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown;
+ (BOOL) isRemoteAvailable;
@end

View File

@ -0,0 +1,517 @@
/*****************************************************************************
* HIDRemoteControlDevice.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "HIDRemoteControlDevice.h"
#import <mach/mach.h>
#import <mach/mach_error.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDKeys.h>
#import <Carbon/Carbon.h>
@interface HIDRemoteControlDevice (PrivateMethods)
- (NSDictionary*) cookieToButtonMapping;
- (IOHIDQueueInterface**) queue;
- (IOHIDDeviceInterface**) hidDeviceInterface;
- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues;
- (void) removeNotifcationObserver;
- (void) remoteControlAvailable:(NSNotification *)notification;
@end
@interface HIDRemoteControlDevice (IOKitMethods)
+ (io_object_t) findRemoteDevice;
- (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice;
- (BOOL) initializeCookies;
- (BOOL) openDevice;
@end
@implementation HIDRemoteControlDevice
+ (const char*) remoteControlDeviceName {
return "";
}
+ (BOOL) isRemoteAvailable {
io_object_t hidDevice = [self findRemoteDevice];
if (hidDevice != 0) {
IOObjectRelease(hidDevice);
return YES;
} else {
return NO;
}
}
- (id) initWithDelegate: (id) _remoteControlDelegate {
if (self = [super initWithDelegate:_remoteControlDelegate]) {
if (![[self class] isRemoteAvailable]) {
[self release];
self = nil;
} else {
openInExclusiveMode = YES;
queue = NULL;
hidDeviceInterface = NULL;
cookieToButtonMapping = [NSMutableDictionary new];
[self setCookieMappingInDictionary: cookieToButtonMapping];
NSEnumerator* enumerator = [cookieToButtonMapping objectEnumerator];
NSNumber* identifier;
supportedButtonEvents = 0;
while(identifier = [enumerator nextObject]) {
supportedButtonEvents |= [identifier intValue];
}
fixSecureEventInputBug = [[NSUserDefaults standardUserDefaults] boolForKey: @"remoteControlWrapperFixSecureEventInputBug"];
}
}
return self;
}
- (void) dealloc {
[self removeNotifcationObserver];
[self stopListening:self];
[cookieToButtonMapping release];
[super dealloc];
}
- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
[delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self];
}
- (void) setCookieMappingInDictionary: (NSMutableDictionary*) cookieToButtonMapping {
}
- (int) remoteIdSwitchCookie {
return 0;
}
- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
return (supportedButtonEvents & identifier) == identifier;
}
- (BOOL) isListeningToRemote {
return (hidDeviceInterface != NULL && allCookies != NULL && queue != NULL);
}
- (void) setListeningToRemote: (BOOL) value {
if (value == NO) {
[self stopListening:self];
} else {
[self startListening:self];
}
}
- (BOOL) isOpenInExclusiveMode {
return openInExclusiveMode;
}
- (void) setOpenInExclusiveMode: (BOOL) value {
openInExclusiveMode = value;
}
- (BOOL) processesBacklog {
return processesBacklog;
}
- (void) setProcessesBacklog: (BOOL) value {
processesBacklog = value;
}
- (IBAction) startListening: (id) sender {
if ([self isListeningToRemote]) return;
// 4th July 2007
//
// A security update in february of 2007 introduced an odd behavior.
// Whenever SecureEventInput is activated or deactivated the exclusive access
// to the remote control device is lost. This leads to very strange behavior where
// a press on the Menu button activates FrontRow while your app still gets the event.
// A great number of people have complained about this.
//
// Enabling the SecureEventInput and keeping it enabled does the trick.
//
// I'm pretty sure this is a kind of bug at Apple and I'm in contact with the responsible
// Apple Engineer. This solution is not a perfect one - I know.
// One of the side effects is that applications that listen for special global keyboard shortcuts (like Quicksilver)
// may get into problems as they no longer get the events.
// As there is no official Apple Remote API from Apple I also failed to open a technical incident on this.
//
// Note that there is a corresponding DisableSecureEventInput in the stopListening method below.
//
if ([self isOpenInExclusiveMode] && fixSecureEventInputBug) EnableSecureEventInput();
[self removeNotifcationObserver];
io_object_t hidDevice = [[self class] findRemoteDevice];
if (hidDevice == 0) return;
if ([self createInterfaceForDevice:hidDevice] == NULL) {
goto error;
}
if ([self initializeCookies]==NO) {
goto error;
}
if ([self openDevice]==NO) {
goto error;
}
// be KVO friendly
[self willChangeValueForKey:@"listeningToRemote"];
[self didChangeValueForKey:@"listeningToRemote"];
goto cleanup;
error:
[self stopListening:self];
DisableSecureEventInput();
cleanup:
IOObjectRelease(hidDevice);
}
- (IBAction) stopListening: (id) sender {
if ([self isListeningToRemote]==NO) return;
BOOL sendNotification = NO;
if (eventSource != NULL) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
CFRelease(eventSource);
eventSource = NULL;
}
if (queue != NULL) {
(*queue)->stop(queue);
//dispose of queue
(*queue)->dispose(queue);
//release the queue we allocated
(*queue)->Release(queue);
queue = NULL;
sendNotification = YES;
}
if (allCookies != nil) {
[allCookies release];
allCookies = nil;
}
if (hidDeviceInterface != NULL) {
//close the device
(*hidDeviceInterface)->close(hidDeviceInterface);
//release the interface
(*hidDeviceInterface)->Release(hidDeviceInterface);
hidDeviceInterface = NULL;
}
if ([self isOpenInExclusiveMode] && fixSecureEventInputBug) DisableSecureEventInput();
if ([self isOpenInExclusiveMode] && sendNotification) {
[[self class] sendFinishedNotifcationForAppIdentifier: nil];
}
// be KVO friendly
[self willChangeValueForKey:@"listeningToRemote"];
[self didChangeValueForKey:@"listeningToRemote"];
}
@end
@implementation HIDRemoteControlDevice (PrivateMethods)
- (IOHIDQueueInterface**) queue {
return queue;
}
- (IOHIDDeviceInterface**) hidDeviceInterface {
return hidDeviceInterface;
}
- (NSDictionary*) cookieToButtonMapping {
return cookieToButtonMapping;
}
- (NSString*) validCookieSubstring: (NSString*) cookieString {
if (cookieString == nil || [cookieString length] == 0) return nil;
NSEnumerator* keyEnum = [[self cookieToButtonMapping] keyEnumerator];
NSString* key;
while(key = [keyEnum nextObject]) {
NSRange range = [cookieString rangeOfString:key];
if (range.location == 0) return key;
}
return nil;
}
- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues {
/*
if (previousRemainingCookieString) {
cookieString = [previousRemainingCookieString stringByAppendingString: cookieString];
NSLog(@"New cookie string is %@", cookieString);
[previousRemainingCookieString release], previousRemainingCookieString=nil;
}*/
if (cookieString == nil || [cookieString length] == 0) return;
NSNumber* buttonId = [[self cookieToButtonMapping] objectForKey: cookieString];
if (buttonId != nil) {
[self sendRemoteButtonEvent: [buttonId intValue] pressedDown: (sumOfValues>0)];
} else {
// let's see if a number of events are stored in the cookie string. this does
// happen when the main thread is too busy to handle all incoming events in time.
NSString* subCookieString;
NSString* lastSubCookieString=nil;
while([subCookieString isEqual:[self validCookieSubstring: cookieString]]) {
cookieString = [cookieString substringFromIndex: [subCookieString length]];
lastSubCookieString = subCookieString;
if (processesBacklog) [self handleEventWithCookieString: subCookieString sumOfValues:sumOfValues];
}
if (processesBacklog == NO && lastSubCookieString != nil) {
// process the last event of the backlog and assume that the button is not pressed down any longer.
// The events in the backlog do not seem to be in order and therefore (in rare cases) the last event might be
// a button pressed down event while in reality the user has released it.
// NSLog(@"processing last event of backlog");
[self handleEventWithCookieString: lastSubCookieString sumOfValues:0];
}
if ([cookieString length] > 0) {
NSLog(@"Unknown button for cookiestring %@", cookieString);
}
}
}
- (void) removeNotifcationObserver {
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION object:nil];
}
- (void) remoteControlAvailable:(NSNotification *)notification {
[self removeNotifcationObserver];
[self startListening: self];
}
@end
/* Callback method for the device queue
Will be called for any event of any type (cookie) to which we subscribe
*/
static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, void* sender) {
if (target < 0) {
NSLog(@"QueueCallbackFunction called with invalid target!");
return;
}
NSAutoreleasePool* pool = [NSAutoreleasePool new];
HIDRemoteControlDevice* remote = (HIDRemoteControlDevice*)target;
IOHIDEventStruct event;
AbsoluteTime zeroTime = {0,0};
NSMutableString* cookieString = [NSMutableString string];
SInt32 sumOfValues = 0;
while (result == kIOReturnSuccess)
{
result = (*[remote queue])->getNextEvent([remote queue], &event, zeroTime, 0);
if ( result != kIOReturnSuccess )
continue;
//printf("%d %d %d\n", event.elementCookie, event.value, event.longValue);
if (((int)event.elementCookie)!=5) {
sumOfValues+=event.value;
[cookieString appendString:[NSString stringWithFormat:@"%d_", event.elementCookie]];
}
}
[remote handleEventWithCookieString: cookieString sumOfValues: sumOfValues];
[pool release];
}
@implementation HIDRemoteControlDevice (IOKitMethods)
- (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice {
io_name_t className;
IOCFPlugInInterface** plugInInterface = NULL;
HRESULT plugInResult = S_OK;
SInt32 score = 0;
IOReturn ioReturnValue = kIOReturnSuccess;
hidDeviceInterface = NULL;
ioReturnValue = IOObjectGetClass(hidDevice, className);
if (ioReturnValue != kIOReturnSuccess) {
NSLog(@"Error: Failed to get class name.");
return NULL;
}
ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice,
kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterface,
&score);
if (ioReturnValue == kIOReturnSuccess)
{
//Call a method of the intermediate plug-in to create the device interface
plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID) &hidDeviceInterface);
if (plugInResult != S_OK) {
NSLog(@"Error: Couldn't create HID class device interface");
}
// Release
if (plugInInterface) (*plugInInterface)->Release(plugInInterface);
}
return hidDeviceInterface;
}
- (BOOL) initializeCookies {
IOHIDDeviceInterface122** handle = (IOHIDDeviceInterface122**)hidDeviceInterface;
IOHIDElementCookie cookie;
long usage;
long usagePage;
id object;
NSArray* elements = nil;
NSDictionary* element;
IOReturn success;
if (!handle || !(*handle)) return NO;
// Copy all elements, since we're grabbing most of the elements
// for this device anyway, and thus, it's faster to iterate them
// ourselves. When grabbing only one or two elements, a matching
// dictionary should be passed in here instead of NULL.
success = (*handle)->copyMatchingElements(handle, NULL, (CFArrayRef*)&elements);
if (success == kIOReturnSuccess) {
[elements autorelease];
/*
cookies = calloc(NUMBER_OF_APPLE_REMOTE_ACTIONS, sizeof(IOHIDElementCookie));
memset(cookies, 0, sizeof(IOHIDElementCookie) * NUMBER_OF_APPLE_REMOTE_ACTIONS);
*/
allCookies = [NSMutableArray new];
NSEnumerator *elementsEnumerator = [elements objectEnumerator];
while (element = [elementsEnumerator nextObject]) {
//Get cookie
object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementCookieKey) ];
if (object == nil || ![object isKindOfClass:[NSNumber class]]) continue;
if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue;
cookie = (IOHIDElementCookie) [object longValue];
//Get usage
object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementUsageKey) ];
if (object == nil || ![object isKindOfClass:[NSNumber class]]) continue;
usage = [object longValue];
//Get usage page
object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementUsagePageKey) ];
if (object == nil || ![object isKindOfClass:[NSNumber class]]) continue;
usagePage = [object longValue];
[allCookies addObject: [NSNumber numberWithInt:(int)cookie]];
}
} else {
return NO;
}
return YES;
}
- (BOOL) openDevice {
HRESULT result;
IOHIDOptionsType openMode = kIOHIDOptionsTypeNone;
if ([self isOpenInExclusiveMode]) openMode = kIOHIDOptionsTypeSeizeDevice;
IOReturn ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, openMode);
if (ioReturnValue == KERN_SUCCESS) {
queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface);
if (queue) {
result = (*queue)->create(queue, 0, 12); //depth: maximum number of elements in queue before oldest elements in queue begin to be lost.
IOHIDElementCookie cookie;
NSEnumerator *allCookiesEnumerator = [allCookies objectEnumerator];
while ((cookie = (IOHIDElementCookie)[[allCookiesEnumerator nextObject] intValue])!=0) {
(*queue)->addElement(queue, cookie, 0);
}
// add callback for async events
ioReturnValue = (*queue)->createAsyncEventSource(queue, &eventSource);
if (ioReturnValue == KERN_SUCCESS) {
ioReturnValue = (*queue)->setEventCallout(queue,QueueCallbackFunction, self, NULL);
if (ioReturnValue == KERN_SUCCESS) {
CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
//start data delivery to queue
(*queue)->start(queue);
return YES;
} else {
NSLog(@"Error when setting event callback");
}
} else {
NSLog(@"Error when creating async event source");
}
} else {
NSLog(@"Error when opening device");
}
} else if (ioReturnValue == kIOReturnExclusiveAccess) {
// the device is used exclusive by another application
// 1. we register for the FINISHED_USING_REMOTE_CONTROL_NOTIFICATION notification
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteControlAvailable:) name:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION object:nil];
// 2. send a distributed notification that we wanted to use the remote control
[[self class] sendRequestForRemoteControlNotification];
}
return NO;
}
+ (io_object_t) findRemoteDevice {
CFMutableDictionaryRef hidMatchDictionary = NULL;
IOReturn ioReturnValue = kIOReturnSuccess;
io_iterator_t hidObjectIterator = 0;
io_object_t hidDevice = 0;
// Set up a matching dictionary to search the I/O Registry by class
// name for all HID class devices
hidMatchDictionary = IOServiceMatching([self remoteControlDeviceName]);
// Now search I/O Registry for matching devices.
ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, hidMatchDictionary, &hidObjectIterator);
if ((ioReturnValue == kIOReturnSuccess) && (hidObjectIterator != 0)) {
hidDevice = IOIteratorNext(hidObjectIterator);
}
// release the iterator
IOObjectRelease(hidObjectIterator);
return hidDevice;
}
@end

View File

@ -0,0 +1,39 @@
/*****************************************************************************
* KeyspanFrontRowControl.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import "HIDRemoteControlDevice.h"
/* Interacts with the Keyspan FrontRow Remote Control HID device
The class is not thread safe
*/
@interface KeyspanFrontRowControl : HIDRemoteControlDevice {
}
@end

View File

@ -0,0 +1,87 @@
/*****************************************************************************
* KeyspanFrontRowControl.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "KeyspanFrontRowControl.h"
#import <mach/mach.h>
#import <mach/mach_error.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <IOKit/hid/IOHIDKeys.h>
@implementation KeyspanFrontRowControl
- (void) setCookieMappingInDictionary: (NSMutableDictionary*) _cookieToButtonMapping {
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"11_18_99_10_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"11_18_98_10_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"11_18_58_10_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"11_18_61_10_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"11_18_96_10_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"11_18_97_10_"];
/* hold events are not being send by this device
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"14_6_4_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"14_6_3_2_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"14_6_14_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Sleep] forKey:@"18_14_6_18_14_6_"];
[_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
*/
}
+ (io_object_t) findRemoteDevice {
CFMutableDictionaryRef hidMatchDictionary = NULL;
IOReturn ioReturnValue = kIOReturnSuccess;
io_iterator_t hidObjectIterator = 0;
io_object_t hidDevice = 0;
SInt32 idVendor = 1741;
SInt32 idProduct = 0x420;
// Set up a matching dictionary to search the I/O Registry by class
// name for all HID class devices
hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVendor);
CFDictionaryAddValue(hidMatchDictionary, CFSTR(kIOHIDVendorIDKey), numberRef);
CFRelease(numberRef);
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idProduct);
CFDictionaryAddValue(hidMatchDictionary, CFSTR(kIOHIDProductIDKey), numberRef);
CFRelease(numberRef);
// Now search I/O Registry for matching devices.
ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, hidMatchDictionary, &hidObjectIterator);
if ((ioReturnValue == kIOReturnSuccess) && (hidObjectIterator != 0)) {
hidDevice = IOIteratorNext(hidObjectIterator);
}
// release the iterator
IOObjectRelease(hidObjectIterator);
return hidDevice;
}
@end

View File

@ -0,0 +1,90 @@
/*****************************************************************************
* MultiClickRemoteBehavior.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import "RemoteControl.h"
/**
A behavior that adds multiclick and hold events on top of a device.
Events are generated and send to a delegate
*/
@interface MultiClickRemoteBehavior : NSObject {
id delegate;
// state for simulating plus/minus hold
BOOL simulateHoldEvents;
BOOL lastEventSimulatedHold;
RemoteControlEventIdentifier lastHoldEvent;
NSTimeInterval lastHoldEventTime;
// state for multi click
unsigned int clickCountEnabledButtons;
NSTimeInterval maxClickTimeDifference;
NSTimeInterval lastClickCountEventTime;
RemoteControlEventIdentifier lastClickCountEvent;
unsigned int eventClickCount;
}
- (id) init;
// Delegates are not retained
- (void) setDelegate: (id) delegate;
- (id) delegate;
// Simulating hold events does deactivate sending of individual requests for pressed down/released.
// Instead special hold events are being triggered when the user is pressing and holding a button for a small period.
// Simulation is activated only for those buttons and remote control that do not have a seperate event already
- (BOOL) simulateHoldEvent;
- (void) setSimulateHoldEvent: (BOOL) value;
// click counting makes it possible to recognize if the user has pressed a button repeatedly
// click counting does delay each event as it has to wait if there is another event (second click)
// therefore there is a slight time difference (maximumClickCountTimeDifference) between a single click
// of the user and the call of your delegate method
// click counting can be enabled individually for specific buttons. Use the property clickCountEnableButtons to
// set the buttons for which click counting shall be enabled
- (BOOL) clickCountingEnabled;
- (void) setClickCountingEnabled: (BOOL) value;
- (unsigned int) clickCountEnabledButtons;
- (void) setClickCountEnabledButtons: (unsigned int)value;
// the maximum time difference till which clicks are recognized as multi clicks
- (NSTimeInterval) maximumClickCountTimeDifference;
- (void) setMaximumClickCountTimeDifference: (NSTimeInterval) timeDiff;
@end
/*
* Method definitions for the delegate of the MultiClickRemoteBehavior class
*/
@interface NSObject(MultiClickRemoteBehaviorDelegate)
- (void) remoteButton: (RemoteControlEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown clickCount: (unsigned int) count;
@end

View File

@ -0,0 +1,210 @@
/*****************************************************************************
* MultiClickRemoteBehavior.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "MultiClickRemoteBehavior.h"
const NSTimeInterval DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE=0.35;
const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
@implementation MultiClickRemoteBehavior
- (id) init {
if (self = [super init]) {
maxClickTimeDifference = DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE;
}
return self;
}
// Delegates are not retained!
// http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/chapter_6_section_4.html
// Delegating objects do not (and should not) retain their delegates.
// However, clients of delegating objects (applications, usually) are responsible for ensuring that their delegates are around
// to receive delegation messages. To do this, they may have to retain the delegate.
- (void) setDelegate: (id) _delegate {
if (_delegate && [_delegate respondsToSelector:@selector(remoteButton:pressedDown:clickCount:)]==NO) return;
delegate = _delegate;
}
- (id) delegate {
return delegate;
}
- (BOOL) simulateHoldEvent {
return simulateHoldEvents;
}
- (void) setSimulateHoldEvent: (BOOL) value {
simulateHoldEvents = value;
}
- (BOOL) simulatesHoldForButtonIdentifier: (RemoteControlEventIdentifier) identifier remoteControl: (RemoteControl*) remoteControl {
// we do that check only for the normal button identifiers as we would check for hold support for hold events instead
if (identifier > (1 << EVENT_TO_HOLD_EVENT_OFFSET)) return NO;
return [self simulateHoldEvent] && [remoteControl sendsEventForButtonIdentifier: (identifier << EVENT_TO_HOLD_EVENT_OFFSET)]==NO;
}
- (BOOL) clickCountingEnabled {
return clickCountEnabledButtons != 0;
}
- (void) setClickCountingEnabled: (BOOL) value {
if (value) {
[self setClickCountEnabledButtons: kRemoteButtonPlus | kRemoteButtonMinus | kRemoteButtonPlay | kRemoteButtonLeft | kRemoteButtonRight | kRemoteButtonMenu];
} else {
[self setClickCountEnabledButtons: 0];
}
}
- (unsigned int) clickCountEnabledButtons {
return clickCountEnabledButtons;
}
- (void) setClickCountEnabledButtons: (unsigned int)value {
clickCountEnabledButtons = value;
}
- (NSTimeInterval) maximumClickCountTimeDifference {
return maxClickTimeDifference;
}
- (void) setMaximumClickCountTimeDifference: (NSTimeInterval) timeDiff {
maxClickTimeDifference = timeDiff;
}
- (void) sendSimulatedHoldEvent: (id) time {
BOOL startSimulateHold = NO;
RemoteControlEventIdentifier event = lastHoldEvent;
@synchronized(self) {
startSimulateHold = (lastHoldEvent>0 && lastHoldEventTime == [time doubleValue]);
}
if (startSimulateHold) {
lastEventSimulatedHold = YES;
event = (event << EVENT_TO_HOLD_EVENT_OFFSET);
[delegate remoteButton:event pressedDown: YES clickCount: 1];
}
}
- (void) executeClickCountEvent: (NSArray*) values {
RemoteControlEventIdentifier event = [[values objectAtIndex: 0] unsignedIntValue];
NSTimeInterval eventTimePoint = [[values objectAtIndex: 1] doubleValue];
BOOL finishedClicking = NO;
int finalClickCount = eventClickCount;
@synchronized(self) {
finishedClicking = (event != lastClickCountEvent || eventTimePoint == lastClickCountEventTime);
if (finishedClicking) {
eventClickCount = 0;
lastClickCountEvent = 0;
lastClickCountEventTime = 0;
}
}
if (finishedClicking) {
[delegate remoteButton:event pressedDown: YES clickCount:finalClickCount];
// trigger a button release event, too
[NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
[delegate remoteButton:event pressedDown: NO clickCount:finalClickCount];
}
}
- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown remoteControl: (RemoteControl*) remoteControl {
if (!delegate) return;
BOOL clickCountingForEvent = ([self clickCountEnabledButtons] & event) == event;
if ([self simulatesHoldForButtonIdentifier: event remoteControl: remoteControl] && lastClickCountEvent==0) {
if (pressedDown) {
// wait to see if it is a hold
lastHoldEvent = event;
lastHoldEventTime = [NSDate timeIntervalSinceReferenceDate];
[self performSelector:@selector(sendSimulatedHoldEvent:)
withObject:[NSNumber numberWithDouble:lastHoldEventTime]
afterDelay:HOLD_RECOGNITION_TIME_INTERVAL];
return;
} else {
if (lastEventSimulatedHold) {
// it was a hold
// send an event for "hold release"
event = (event << EVENT_TO_HOLD_EVENT_OFFSET);
lastHoldEvent = 0;
lastEventSimulatedHold = NO;
[delegate remoteButton:event pressedDown: pressedDown clickCount:1];
return;
} else {
RemoteControlEventIdentifier previousEvent = lastHoldEvent;
@synchronized(self) {
lastHoldEvent = 0;
}
// in case click counting is enabled we have to setup the state for that, too
if (clickCountingForEvent) {
lastClickCountEvent = previousEvent;
lastClickCountEventTime = lastHoldEventTime;
NSNumber* eventNumber;
NSNumber* timeNumber;
eventClickCount = 1;
timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime];
eventNumber= [NSNumber numberWithUnsignedInt:previousEvent];
NSTimeInterval diffTime = maxClickTimeDifference-([NSDate timeIntervalSinceReferenceDate]-lastHoldEventTime);
[self performSelector: @selector(executeClickCountEvent:)
withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil]
afterDelay: diffTime];
// we do not return here because we are still in the press-release event
// that will be consumed below
} else {
// trigger the pressed down event that we consumed first
[delegate remoteButton:event pressedDown: YES clickCount:1];
}
}
}
}
if (clickCountingForEvent) {
if (pressedDown == NO) return;
NSNumber* eventNumber;
NSNumber* timeNumber;
@synchronized(self) {
lastClickCountEventTime = [NSDate timeIntervalSinceReferenceDate];
if (lastClickCountEvent == event) {
eventClickCount = eventClickCount + 1;
} else {
eventClickCount = 1;
}
lastClickCountEvent = event;
timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime];
eventNumber= [NSNumber numberWithUnsignedInt:event];
}
[self performSelector: @selector(executeClickCountEvent:)
withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil]
afterDelay: maxClickTimeDifference];
} else {
[delegate remoteButton:event pressedDown: pressedDown clickCount:1];
}
}
@end

View File

@ -0,0 +1,102 @@
/*****************************************************************************
* RemoteControl.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
// notifaction names that are being used to signal that an application wants to
// have access to the remote control device or if the application has finished
// using the remote control device
extern NSString* REQUEST_FOR_REMOTE_CONTROL_NOTIFCATION;
extern NSString* FINISHED_USING_REMOTE_CONTROL_NOTIFICATION;
// keys used in user objects for distributed notifications
extern NSString* kRemoteControlDeviceName;
extern NSString* kApplicationIdentifier;
extern NSString* kTargetApplicationIdentifier;
// we have a 6 bit offset to make a hold event out of a normal event
#define EVENT_TO_HOLD_EVENT_OFFSET 6
@class RemoteControl;
typedef enum _RemoteControlEventIdentifier {
// normal events
kRemoteButtonPlus =1<<1,
kRemoteButtonMinus =1<<2,
kRemoteButtonMenu =1<<3,
kRemoteButtonPlay =1<<4,
kRemoteButtonRight =1<<5,
kRemoteButtonLeft =1<<6,
// hold events
kRemoteButtonPlus_Hold =1<<7,
kRemoteButtonMinus_Hold =1<<8,
kRemoteButtonMenu_Hold =1<<9,
kRemoteButtonPlay_Hold =1<<10,
kRemoteButtonRight_Hold =1<<11,
kRemoteButtonLeft_Hold =1<<12,
// special events (not supported by all devices)
kRemoteControl_Switched =1<<13,
} RemoteControlEventIdentifier;
@interface NSObject(RemoteControlDelegate)
- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown remoteControl: (RemoteControl*) remoteControl;
@end
/*
Base Interface for Remote Control devices
*/
@interface RemoteControl : NSObject {
id delegate;
}
// returns nil if the remote control device is not available
- (id) initWithDelegate: (id) remoteControlDelegate;
- (void) setListeningToRemote: (BOOL) value;
- (BOOL) isListeningToRemote;
- (BOOL) isOpenInExclusiveMode;
- (void) setOpenInExclusiveMode: (BOOL) value;
- (IBAction) startListening: (id) sender;
- (IBAction) stopListening: (id) sender;
// is this remote control sending the given event?
- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier;
// sending of notifications between applications
+ (void) sendFinishedNotifcationForAppIdentifier: (NSString*) identifier;
+ (void) sendRequestForRemoteControlNotification;
// name of the device
+ (const char*) remoteControlDeviceName;
@end

View File

@ -0,0 +1,103 @@
/*****************************************************************************
* RemoteControl.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "RemoteControl.h"
// notifaction names that are being used to signal that an application wants to
// have access to the remote control device or if the application has finished
// using the remote control device
NSString* REQUEST_FOR_REMOTE_CONTROL_NOTIFCATION = @"mac.remotecontrols.RequestForRemoteControl";
NSString* FINISHED_USING_REMOTE_CONTROL_NOTIFICATION = @"mac.remotecontrols.FinishedUsingRemoteControl";
// keys used in user objects for distributed notifications
NSString* kRemoteControlDeviceName = @"RemoteControlDeviceName";
NSString* kApplicationIdentifier = @"CFBundleIdentifier";
// bundle identifier of the application that should get access to the remote control
// this key is being used in the FINISHED notification only
NSString* kTargetApplicationIdentifier = @"TargetBundleIdentifier";
@implementation RemoteControl
// returns nil if the remote control device is not available
- (id) initWithDelegate: (id) _remoteControlDelegate {
if (self = [super init]) {
delegate = [_remoteControlDelegate retain];
}
return self;
}
- (void) dealloc {
[delegate release];
[super dealloc];
}
- (void) setListeningToRemote: (BOOL) value {
}
- (BOOL) isListeningToRemote {
return NO;
}
- (IBAction) startListening: (id) sender {
}
- (IBAction) stopListening: (id) sender {
}
- (BOOL) isOpenInExclusiveMode {
return YES;
}
- (void) setOpenInExclusiveMode: (BOOL) value {
}
- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
return YES;
}
+ (void) sendDistributedNotification: (NSString*) notificationName targetBundleIdentifier: (NSString*) targetIdentifier {
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithCString:[self remoteControlDeviceName] encoding:NSASCIIStringEncoding],
kRemoteControlDeviceName, [[NSBundle mainBundle] bundleIdentifier], kApplicationIdentifier,
targetIdentifier, kTargetApplicationIdentifier, nil];
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:notificationName
object:nil
userInfo:userInfo
deliverImmediately:YES];
}
+ (void) sendFinishedNotifcationForAppIdentifier: (NSString*) identifier {
[self sendDistributedNotification:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION targetBundleIdentifier:identifier];
}
+ (void) sendRequestForRemoteControlNotification {
[self sendDistributedNotification:REQUEST_FOR_REMOTE_CONTROL_NOTIFCATION targetBundleIdentifier:nil];
}
+ (const char*) remoteControlDeviceName {
return NULL;
}
@end

View File

@ -0,0 +1,38 @@
/*****************************************************************************
* RemoteControlContainer.h
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import <Cocoa/Cocoa.h>
#import "RemoteControl.h"
@interface RemoteControlContainer : RemoteControl {
NSMutableArray* remoteControls;
}
- (BOOL)addRemoteControlDevice:(RemoteControl *)theRemote;
- (unsigned int) count;
@end

View File

@ -0,0 +1,107 @@
/*****************************************************************************
* RemoteControlContainer.m
* RemoteControlWrapper
*
* Created by Martin Kahr on 11.03.06 under a MIT-style license.
* Copyright (c) 2006 martinkahr.com. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*****************************************************************************/
#import "RemoteControlContainer.h"
@implementation RemoteControlContainer
- (id) initWithDelegate: (id) _remoteControlDelegate {
if (self = [super initWithDelegate:_remoteControlDelegate]) {
remoteControls = [NSMutableArray new];
}
return self;
}
- (void) dealloc {
[self stopListening: self];
[remoteControls release];
[super dealloc];
}
- (BOOL)addRemoteControlDevice:(RemoteControl *)theRemote {
if (theRemote) {
[remoteControls addObject: theRemote];
[theRemote addObserver: self forKeyPath:@"listeningToRemote" options:NSKeyValueObservingOptionNew context:nil];
return YES;
}
return NO;
}
- (unsigned int) count {
return [remoteControls count];
}
- (void) reset {
[self willChangeValueForKey:@"listeningToRemote"];
[self didChangeValueForKey:@"listeningToRemote"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[self reset];
}
- (void) setListeningToRemote: (BOOL) value {
for(int i=0; i < [remoteControls count]; i++) {
[[remoteControls objectAtIndex: i] setListeningToRemote: value];
}
if (value && value != [self isListeningToRemote]) [self performSelector:@selector(reset) withObject:nil afterDelay:0.01];
}
- (BOOL) isListeningToRemote {
for(int i=0; i < [remoteControls count]; i++) {
if ([[remoteControls objectAtIndex: i] isListeningToRemote]) {
return YES;
}
}
return NO;
}
- (IBAction) startListening: (id) sender {
for(int i=0; i < [remoteControls count]; i++) {
[[remoteControls objectAtIndex: i] startListening: sender];
}
}
- (IBAction) stopListening: (id) sender {
for(int i=0; i < [remoteControls count]; i++) {
[[remoteControls objectAtIndex: i] stopListening: sender];
}
}
- (BOOL) isOpenInExclusiveMode {
BOOL mode = YES;
for(int i=0; i < [remoteControls count]; i++) {
mode = mode && ([[remoteControls objectAtIndex: i] isOpenInExclusiveMode]);
}
return mode;
}
- (void) setOpenInExclusiveMode: (BOOL) value {
for(int i=0; i < [remoteControls count]; i++) {
[[remoteControls objectAtIndex: i] setOpenInExclusiveMode:value];
}
}
@end

View File

@ -0,0 +1,108 @@
//
// MGMTaskManager.h
// YouView
//
// Created by Mr. Gecko on 4/16/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMURL;
extern NSString * const MGMPreviewURL;
extern NSString * const MGMFilePath;
extern NSString * const MGMYVTaskPath;
extern NSString * const MGMFileName;
extern NSString * const MGMConverting;
extern NSString * const MGMConvertPath;
extern NSString * const MGMConvertFormat;
extern NSString * const MGMDonePath;
extern NSString * const MGMRevealPath;
extern NSString * const MGMTime;
extern NSString * const MGMFExtension;
extern NSString * const MGMFArguments;
extern NSString * const MGMFAudio;
extern NSString * const MGMMediaInfoKey;
extern NSString * const MGMTypeKey;
extern NSString * const MGMTypeGeneralKey;
extern NSString * const MGMTypeVideoKey;
extern NSString * const MGMTypeAudioKey;
extern NSString * const MGMBitrateKey;
extern NSString * const MGMCustomBitrateKey;
extern NSString * const MGMStreamKindIDKey;
extern NSString * const MGMIDKey;
extern NSString * const MGMLanguageKey;
extern NSString * const MGMFormatKey;
extern NSString * const MGMFileSizeKey;
extern NSString * const MGMFormatKey;
extern NSString * const MGMFormatProfileKey;
extern NSString * const MGMOveralBitRateKey;
extern NSString * const MGMPlayTimeKey;
extern NSString * const MGMCodecProfileKey;
extern NSString * const MGMDisplayAspectRatioKey;
extern NSString * const MGMFrameRateKey;
extern NSString * const MGMHeightKey;
extern NSString * const MGMWidthKey;
extern NSString * const MGMCustomHeightKey;
extern NSString * const MGMCustomWidthKey;
extern NSString * const MGMPixelAspectRatioKey;
extern NSString * const MGMScanOrderKey;
extern NSString * const MGMScanTypeKey;
extern NSString * const MGMSamplingRateKey;
extern NSString * const MGMMaxQualityKey;
extern NSString * const MGMInfoPlist;
extern NSString * const MGMYVTaskExt;
extern NSString * const MGMMP4Ext;
extern NSString * const MGMM4VExt;
extern NSString * const MGMMOVExt;
extern NSString * const MGMWMVExt;
extern NSString * const MGMAVIExt;
extern NSString * const MGMFLVExt;
extern NSString * const MGMMKVExt;
extern NSString * const MGMDVExt;
extern NSString * const MGMMPGExt;
extern NSString * const MGMMP3Ext;
extern NSString * const MGMM4AExt;
extern NSString * const MGMWAVExt;
extern NSString * const MGMAIFFExt;
extern NSString * const MGMAIFExt;
extern NSString * const MGMWMAExt;
extern NSString * const MGMJPGExt;
@class MGMTaskView, MGMController;
@interface MGMTaskManager : NSObject {
IBOutlet MGMController *controller;
IBOutlet NSView *exportView;
IBOutlet NSMatrix *maxQuality;
IBOutlet NSPopUpButton *exportFormat;
IBOutlet NSPopUpButton *videoFormat;
IBOutlet NSPopUpButton *audioFormat;
IBOutlet NSTextField *widthField;
IBOutlet NSTextField *heightField;
IBOutlet NSTextField *bitrateField;
IBOutlet NSWindow *mainWindow;
IBOutlet NSTableView *taskTable;
IBOutlet NSTextField *numTasks;
NSMutableArray *tasks;
NSMutableArray *formats;
}
- (MGMController *)controller;
- (NSArray *)formats;
- (void)updateCount;
- (IBAction)showTaskManager:(id)sender;
- (IBAction)clear:(id)sender;
- (void)addTask:(NSDictionary *)task withVideo:(NSURL *)video;
- (BOOL)ableToConvert:(MGMTaskView *)sender;
- (void)nextConversion;
- (void)saveEntry:(NSURL *)theEntry title:(NSString *)theTitle;
@end

View File

@ -0,0 +1,297 @@
//
// MGMTaskManager.m
// YouView
//
// Created by Mr. Gecko on 4/16/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMTaskManager.h"
#import "MGMTaskView.h"
#import "MGMController.h"
#import "MGMViewCell.h"
#import <GeckoReporter/GeckoReporter.h>
NSString * const MGMURL = @"TaskURL";
NSString * const MGMPreviewURL = @"TaskPreviewURL";
NSString * const MGMFilePath = @"TaskFilePath";
NSString * const MGMYVTaskPath = @"TaskYVTaskPath";
NSString * const MGMFileName = @"TaskFileName";
NSString * const MGMConverting = @"TaskConverting";
NSString * const MGMConvertPath = @"TaskConvertPath";
NSString * const MGMConvertFormat = @"TaskConvertFormat";
NSString * const MGMDonePath = @"TaskDonePath";
NSString * const MGMRevealPath = @"TaskRevealPath";
NSString * const MGMTime = @"TaskTime";
NSString * const MGMFExtension = @"FormatExtension";
NSString * const MGMFArguments = @"FormatArguments";
NSString * const MGMFAudio = @"FormatAudio";
NSString * const MGMMediaInfoKey = @"MediaInfo";
NSString * const MGMTypeKey = @"Type";
NSString * const MGMTypeGeneralKey = @"General";
NSString * const MGMTypeVideoKey = @"Video";
NSString * const MGMTypeAudioKey = @"Audio";
NSString * const MGMBitrateKey = @"Bitrate";
NSString * const MGMCustomBitrateKey = @"CustomBitrate";
NSString * const MGMStreamKindIDKey = @"StreamKindID";
NSString * const MGMIDKey = @"ID";
NSString * const MGMLanguageKey = @"Language";
NSString * const MGMFormatKey = @"Format";
NSString * const MGMFileSizeKey = @"FileSize";
NSString * const MGMFormatProfileKey = @"Format_Profile";
NSString * const MGMOveralBitRateKey = @"OveralBitrate";
NSString * const MGMPlayTimeKey = @"PlayTime";
NSString * const MGMCodecProfileKey = @"Codec_Profile";
NSString * const MGMDisplayAspectRatioKey = @"DisplayAspectRatio";
NSString * const MGMFrameRateKey = @"FrameRate";
NSString * const MGMHeightKey = @"Height";
NSString * const MGMWidthKey = @"Width";
NSString * const MGMCustomHeightKey = @"CustomHeight";
NSString * const MGMCustomWidthKey = @"CustomWidth";
NSString * const MGMPixelAspectRatioKey = @"PixelAspectRatio";
NSString * const MGMScanOrderKey = @"ScanOrder";
NSString * const MGMScanTypeKey = @"ScanType";
NSString * const MGMSamplingRateKey = @"SamplingRate";
NSString * const MGMMaxQualityKey = @"MaxQuality";
NSString * const MGMInfoPlist = @"info.plist";
NSString * const MGMYVTaskExt = @"yvtask";
NSString * const MGMMP4Ext = @"mp4";
NSString * const MGMM4VExt = @"m4v";
NSString * const MGMMOVExt = @"mov";
NSString * const MGMWMVExt = @"wmv";
NSString * const MGMAVIExt = @"avi";
NSString * const MGMFLVExt = @"flv";
NSString * const MGMMKVExt = @"mkv";
NSString * const MGMDVExt = @"dv";
NSString * const MGMMPGExt = @"mpg";
NSString * const MGMMP3Ext = @"mp3";
NSString * const MGMM4AExt = @"m4a";
NSString * const MGMWAVExt = @"wav";
NSString * const MGMAIFFExt = @"aiff";
NSString * const MGMAIFExt = @"aif";
NSString * const MGMWMAExt = @"wma";
NSString * const MGMJPGExt = @"jpg";
@protocol NSSavePanelProtocol <NSObject>
- (NSInteger)runModalForDirectory:(NSString *)path file:(NSString *)filename;
- (void)setNameFieldStringValue:(NSString *)value;
- (void)setDirectoryURL:(NSURL *)url;
@end
@implementation MGMTaskManager
- (void)awakeFromNib {
formats = [NSMutableArray new];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMMP4Ext, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"mpeg4", @"-acodec", @"libfaac", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMMOVExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"libx264", @"-acodec", @"libfaac", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMFLVExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"flv", @"-acodec", @"libmp3lame", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"swf", MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"flv", @"-acodec", @"libmp3lame", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMAVIExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"mpeg4", @"-acodec", @"libmp3lame", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMAVIExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"msmpeg4v2", @"-acodec", @"libmp3lame", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMM4VExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"libx264", @"-acodec", @"libfaac", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMMPGExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"mpeg1video", @"-acodec", @"mp2", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMWMVExt, MGMFExtension, [NSArray arrayWithObjects:@"-vcodec", @"wmv2", @"-acodec", @"wmav2", nil], MGMFArguments, [NSNumber numberWithBool:NO], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMMP3Ext, MGMFExtension, [NSArray arrayWithObjects:@"-vn", @"-acodec", @"libmp3lame", nil], MGMFArguments, [NSNumber numberWithBool:YES], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMM4AExt, MGMFExtension, [NSArray arrayWithObjects:@"-vn", @"-acodec", @"libfaac", nil], MGMFArguments, [NSNumber numberWithBool:YES], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMWAVExt, MGMFExtension, [NSArray arrayWithObjects:@"-vn", @"-acodec", @"pcm_s16le", nil], MGMFArguments, [NSNumber numberWithBool:YES], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMAIFFExt, MGMFExtension, [NSArray arrayWithObjects:@"-vn", @"-acodec", @"pcm_s16be", nil], MGMFArguments, [NSNumber numberWithBool:YES], MGMFAudio, nil]];
[formats addObject:[NSDictionary dictionaryWithObjectsAndKeys:MGMWMAExt, MGMFExtension, [NSArray arrayWithObjects:@"-vn", @"-acodec", @"wmav2", nil], MGMFArguments, [NSNumber numberWithBool:YES], MGMFAudio, nil]];
[[[taskTable tableColumns] objectAtIndex:0] setDataCell:[[MGMViewCell new] autorelease]];
tasks = [NSMutableArray new];
}
- (void)dealloc {
#if releaseDebug
MGMLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
[tasks release];
[formats release];
[super dealloc];
}
- (MGMController *)controller {
return controller;
}
- (NSArray *)formats {
return formats;
}
- (void)reloadData {
while ([[taskTable subviews] count] > 0) {
[[[taskTable subviews] lastObject] removeFromSuperviewWithoutNeedingDisplay];
}
[taskTable reloadData];
}
- (void)updateCount {
[numTasks setStringValue:[NSString stringWithFormat:@"Tasks %d", [tasks count]]];
}
- (IBAction)showTaskManager:(id)sender {
[self updateCount];
[mainWindow makeKeyAndOrderFront:sender];
}
- (IBAction)clear:(id)sender {
for (int i = [tasks count]-1; i>=0; i--) {
if (![[tasks objectAtIndex:i] working]) {
[tasks removeObjectAtIndex:i];
}
}
[self reloadData];
[self updateCount];
}
- (void)addTask:(NSDictionary *)task withVideo:(NSURL *)video {
[tasks addObject:[MGMTaskView taskViewWithTask:task withVideo:video manager:self]];
[self reloadData];
[mainWindow makeKeyAndOrderFront:self];
[self updateCount];
}
- (BOOL)ableToConvert:(MGMTaskView *)sender {
for (int i=0; i<[tasks count]; i++) {
if ([tasks objectAtIndex:i] != sender) {
if ([[tasks objectAtIndex:i] converting]) {
return NO;
}
}
}
return YES;
}
- (void)nextConversion {
for (int i=0; i<[tasks count]; i++) {
if ([[tasks objectAtIndex:i] waitingToConvert]) {
[[tasks objectAtIndex:i] startConverson];
break;
}
}
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [tasks count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
return nil;
}
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
[(MGMViewCell *)cell addSubview:[tasks objectAtIndex:row]];
}
- (void)saveEntry:(NSURL *)theEntry title:(NSString *)theTitle {
[maxQuality selectCellAtRow:0 column:[[NSUserDefaults standardUserDefaults] integerForKey:MGMMaxQuality]];
NSSavePanel<NSSavePanelProtocol> *panel = [NSSavePanel savePanel];
[panel setAccessoryView:exportView];
int returnCode;
if ([[[MGMSystemInfo new] autorelease] isAfterSnowLeopard]) {
[panel setNameFieldStringValue:theTitle];
returnCode = [panel runModal];
} else {
returnCode = [panel runModalForDirectory:nil file:theTitle];
}
if (returnCode==NSOKButton) {
NSString *file = [[panel URL] path];
NSMutableDictionary *taskInfo = [NSMutableDictionary dictionary];
NSString *extension = MGMMP4Ext;
if ([exportFormat indexOfSelectedItem]!=0) {
[taskInfo setObject:[NSNumber numberWithInt:[exportFormat indexOfSelectedItem]-1] forKey:MGMConvertFormat];
extension = [[formats objectAtIndex:[[taskInfo objectForKey:MGMConvertFormat] intValue]] objectForKey:MGMFExtension];
}
[taskInfo setObject:[file stringByAppendingPathExtension:extension] forKey:MGMDonePath];
[taskInfo setObject:[NSNumber numberWithInt:[maxQuality selectedColumn]] forKey:MGMMaxQualityKey];
if (![[widthField stringValue] isEqual:@""])
[taskInfo setObject:[widthField stringValue] forKey:MGMCustomWidthKey];
if (![[heightField stringValue] isEqual:@""])
[taskInfo setObject:[heightField stringValue] forKey:MGMCustomHeightKey];
if (![[bitrateField stringValue] isEqual:@""])
[taskInfo setObject:[bitrateField stringValue] forKey:MGMCustomBitrateKey];
[self addTask:taskInfo withVideo:theEntry];
}
}
- (void)application:(NSApplication *)sender openFiles:(NSArray *)files {
for (int i=0; i<[files count]; i++) {
NSString *file = [files objectAtIndex:i];
NSString *extension = [[file pathExtension] lowercaseString];
if ([extension isEqual:MGMYVTaskExt]) {
BOOL open = YES;
for (int f=0; f<[tasks count]; f++) {
if ([[[tasks objectAtIndex:f] YVTaskPath] isEqual:file]) {
open = NO;
break;
}
}
if (open) {
[tasks addObject:[MGMTaskView taskViewWithTask:[NSDictionary dictionaryWithObject:file forKey:MGMYVTaskPath] withVideo:nil manager:self]];
}
} else {
BOOL isVideo;
NSRect frame = [exportFormat frame];
if ([extension isEqual:MGMMP4Ext] || [extension isEqual:MGMM4VExt] || [extension isEqual:MGMMOVExt] || [extension isEqual:MGMWMVExt] || [extension isEqual:MGMAVIExt] || [extension isEqual:MGMFLVExt] || [extension isEqual:MGMMKVExt] || [extension isEqual:MGMDVExt] || [extension isEqual:MGMMPGExt]) {
isVideo = YES;
[maxQuality setEnabled:NO];
[exportFormat removeFromSuperview];
[exportView addSubview:videoFormat];
[videoFormat setFrame:frame];
} else if ([extension isEqual:MGMMP3Ext] || [extension isEqual:MGMM4AExt] || [extension isEqual:MGMWAVExt] || [extension isEqual:MGMAIFFExt] || [extension isEqual:MGMAIFExt] || [extension isEqual:MGMWMAExt]) {
isVideo = NO;
[maxQuality setEnabled:NO];
[exportFormat removeFromSuperview];
[exportView addSubview:audioFormat];
[audioFormat setFrame:frame];
} else {
NSBeep();
return;
}
NSSavePanel<NSSavePanelProtocol> *panel = [NSSavePanel savePanel];
[panel setAccessoryView:exportView];
int returnCode;
if ([panel respondsToSelector:@selector(runModalForDirectory:file:)]) {
returnCode = [panel runModalForDirectory:[file stringByDeletingLastPathComponent] file:[[file lastPathComponent] stringByDeletingPathExtension]];
} else {
[panel setNameFieldStringValue:[[file lastPathComponent] stringByDeletingPathExtension]];
[panel setDirectoryURL:[NSURL fileURLWithPath:[file stringByDeletingLastPathComponent]]];
returnCode = [panel runModal];
}
if (returnCode==NSOKButton) {
NSString *exportFile = [[panel URL] path];
NSMutableDictionary *taskInfo = [NSMutableDictionary dictionary];
[taskInfo setObject:file forKey:MGMFilePath];
[taskInfo setObject:[NSNumber numberWithInt:(isVideo ? [videoFormat indexOfSelectedItem] : [audioFormat indexOfSelectedItem]+9)] forKey:MGMConvertFormat];
[taskInfo setObject:[exportFile stringByAppendingPathExtension:[[formats objectAtIndex:[[taskInfo objectForKey:MGMConvertFormat] intValue]] objectForKey:MGMFExtension]] forKey:MGMDonePath];
[taskInfo setObject:[NSNumber numberWithInt:[maxQuality selectedColumn]] forKey:MGMMaxQualityKey];
if (![[widthField stringValue] isEqual:@""])
[taskInfo setObject:[widthField stringValue] forKey:MGMCustomWidthKey];
if (![[heightField stringValue] isEqual:@""])
[taskInfo setObject:[heightField stringValue] forKey:MGMCustomHeightKey];
if (![[bitrateField stringValue] isEqual:@""])
[taskInfo setObject:[bitrateField stringValue] forKey:MGMCustomBitrateKey];
[taskInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMConverting];
[tasks addObject:[MGMTaskView taskViewWithTask:taskInfo withVideo:nil manager:self]];
[[tasks lastObject] restart:self];
}
if (isVideo)
[videoFormat removeFromSuperview];
else
[audioFormat removeFromSuperview];
[exportView addSubview:exportFormat];
[exportFormat setFrame:frame];
}
}
[self reloadData];
[mainWindow makeKeyAndOrderFront:sender];
[self updateCount];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
for (int i=0; i<[tasks count]; i++) {
if ([[tasks objectAtIndex:i] working]) {
NSBeginAlertSheet(@"Warning", nil, nil, nil, mainWindow, nil, nil, nil, nil, @"You are still downloading/converting files, please cancel them before you quit.");
return NSTerminateCancel;
}
}
return NSTerminateNow;
}
@end

View File

@ -0,0 +1,64 @@
//
// MGMTaskView.h
// YouView
//
// Created by Mr. Gecko on 4/16/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@class MGMURLConnectionManager, MGMVideoFinder, MGMTaskManager;
@interface MGMTaskView : NSObject {
MGMTaskManager *manager;
IBOutlet NSView *mainView;
IBOutlet NSImageView *icon;
IBOutlet NSTextField *name;
IBOutlet NSProgressIndicator *progress;
IBOutlet NSTextField *info;
IBOutlet NSButton *stop;
IBOutlet NSButton *restart;
NSMutableDictionary *taskInfo;
NSURL *entry;
MGMURLConnectionManager *connectionManager;
MGMVideoFinder *videoFinder;
int startTime;
int bytesReceivedSec;
int bytesReceived;
NSTimer *secCheckTimer;
NSString *receivedSec;
int receivedContentLength;
int expectedContentLength;
NSTask *aTask;
NSPipe *taskPipe;
double time;
double videoPlayTime;
double videoFrameRate;
BOOL waitingToConvert;
BOOL converting;
BOOL working;
BOOL stopped;
}
+ (id)taskViewWithTask:(NSDictionary *)theTask withVideo:(NSURL *)theVideo manager:(MGMTaskManager *)theManager;
- (id)initWithTask:(NSDictionary *)theTask withVideo:(NSURL *)theVideo manager:(MGMTaskManager *)theManager;
- (void)setName;
- (NSString *)YVTaskPath;
- (BOOL)working;
- (BOOL)converting;
- (BOOL)waitingToConvert;
- (NSView *)view;
- (NSString *)bytesToString:(double)bytes;
- (NSString *)secsToString:(int)secs;
- (void)convertProcessFinish:(NSNotification *)note;
- (void)convertProcessResponse:(NSString*)response;
- (void)convertProcessRead:(NSNotification *)note;
- (IBAction)stop:(id)sender;
- (IBAction)reveal:(id)sender;
- (IBAction)restart:(id)sender;
- (void)saveInfo;
- (void)startConverson;
@end

View File

@ -0,0 +1,664 @@
//
// MGMTaskView.m
// YouView
//
// Created by Mr. Gecko on 4/16/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMTaskView.h"
#import "MGMTaskManager.h"
#import "MGMAddons.h"
#import "MGMVideoFinder.h"
#import "MGMParentalControls.h"
#import "MGMController.h"
#import <MGMUsers/MGMUsers.h>
#import <GeckoReporter/GeckoReporter.h>
#import <sys/sysctl.h>
@implementation MGMTaskView
+ (id)taskViewWithTask:(NSDictionary *)theTask withVideo:(NSURL *)theVideo manager:(MGMTaskManager *)theManager {
return [[[self alloc] initWithTask:theTask withVideo:theVideo manager:theManager] autorelease];
}
- (id)initWithTask:(NSDictionary *)theTask withVideo:(NSURL *)theVideo manager:(MGMTaskManager *)theManager {
if (self = [super init]) {
manager = [theManager retain];
if (![NSBundle loadNibNamed:@"MGMTaskView" owner:self]) {
[self release];
self = nil;
} else {
connectionManager = [[MGMURLConnectionManager manager] retain];
[connectionManager setUserAgent:MGMUserAgent];
if (theVideo!=nil) {
entry = [theVideo retain];
taskInfo = [[NSMutableDictionary dictionaryWithDictionary:theTask] retain];
[taskInfo setObject:[[taskInfo objectForKey:MGMDonePath] lastPathComponent] forKey:MGMFileName];
[taskInfo setObject:[[taskInfo objectForKey:MGMDonePath] stringByAppendingPathExtension:MGMYVTaskExt] forKey:MGMYVTaskPath];
[taskInfo setObject:[[taskInfo objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:[[[taskInfo objectForKey:MGMFileName] stringByDeletingPathExtension] stringByAppendingPathExtension:MGMMP4Ext]] forKey:MGMFilePath];
[taskInfo setObject:[taskInfo objectForKey:MGMYVTaskPath] forKey:MGMRevealPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createDirectoryAtPath:[taskInfo objectForKey:MGMYVTaskPath] withAttributes:nil];
NSString *imageURL = [NSString stringWithFormat:MGMYTImageURL, [entry URLParameterWithName:@"v"]];
[taskInfo setObject:imageURL forKey:MGMPreviewURL];
[progress setHidden:NO];
[progress startAnimation:self];
[progress setIndeterminate:YES];
[restart setHidden:YES];
[stop setHidden:NO];
startTime = [[NSDate date] timeIntervalSince1970];
[taskInfo setObject:[entry absoluteString] forKey:MGMURL];
[self setName];
videoFinder = [[MGMVideoFinder alloc] initWithURL:[NSURL URLWithString:[taskInfo objectForKey:MGMURL]] connectionManager:connectionManager maxQuality:[[taskInfo objectForKey:MGMMaxQualityKey] intValue] delegate:self];
} else if ([theTask objectForKey:MGMYVTaskPath]!=nil) {
if ([[NSFileManager defaultManager] fileExistsAtPath:[[theTask objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:MGMInfoPlist]]) {
taskInfo = [[NSMutableDictionary dictionaryWithContentsOfFile:[[theTask objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:MGMInfoPlist]] retain];
if (![[taskInfo objectForKey:MGMYVTaskPath] isEqual:[theTask objectForKey:MGMYVTaskPath]]) {
NSString *lastPath = [taskInfo objectForKey:MGMYVTaskPath];
[taskInfo setObject:[theTask objectForKey:MGMYVTaskPath] forKey:MGMYVTaskPath];
if ([lastPath isEqual:[[taskInfo objectForKey:MGMFilePath] stringByDeletingLastPathComponent]]) {
[taskInfo setObject:[[taskInfo objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:[[taskInfo objectForKey:MGMFilePath] lastPathComponent]] forKey:MGMFilePath];
}
[taskInfo setObject:[[[taskInfo objectForKey:MGMYVTaskPath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:[taskInfo objectForKey:MGMFileName]] forKey:MGMDonePath];
[taskInfo setObject:[taskInfo objectForKey:MGMYVTaskPath] forKey:MGMRevealPath];
}
[self setName];
[info setStringValue:@"Click restart to start"];
[stop setHidden:YES];
[restart setHidden:NO];
[progress setHidden:YES];
} else {
NSBeep();
[self release];
self = nil;
}
} else if ([theTask objectForKey:MGMFilePath]!=nil) {
taskInfo = [[NSMutableDictionary dictionaryWithDictionary:theTask] retain];
[taskInfo setObject:[[taskInfo objectForKey:MGMDonePath] lastPathComponent] forKey:MGMFileName];
[taskInfo setObject:[[taskInfo objectForKey:MGMDonePath] stringByAppendingPathExtension:MGMYVTaskExt] forKey:MGMYVTaskPath];
[taskInfo setObject:[taskInfo objectForKey:MGMYVTaskPath] forKey:MGMRevealPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createDirectoryAtPath:[taskInfo objectForKey:MGMYVTaskPath] withAttributes:nil];
[self setName];
} else {
NSBeep();
[self release];
self = nil;
}
if ([taskInfo objectForKey:MGMPreviewURL]!=nil) {
#if youviewdebug
MGMLog(@"URL: %@", [taskInfo objectForKey:MGMPreviewURL]);
#endif
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[taskInfo objectForKey:MGMPreviewURL]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:theRequest delegate:self];
[handler setFailWithError:@selector(iconLoader:didFailWithError:)];
[handler setFinish:@selector(iconLoaderDidFinish:)];
[connectionManager addHandler:handler];
} else {
[icon setImage:[NSImage imageNamed:@"YouViewA"]];
}
}
}
return self;
}
- (void)dealloc {
#if releaseDebug
MGMLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
[manager release];
[mainView release];
[taskInfo release];
[entry release];
[connectionManager cancelAll];
[connectionManager release];
[videoFinder release];
[secCheckTimer invalidate];
[secCheckTimer release];
[receivedSec release];
[aTask terminate];
[aTask release];
[taskPipe release];
[super dealloc];
}
- (void)iconLoader:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)theError {
NSLog(@"Error loading image: %@", theError);
}
- (void)iconLoaderDidFinish:(MGMURLBasicHandler *)theHandler {
NSImage *image = [[[NSImage alloc] initWithData:[theHandler data]] autorelease];
[icon setImage:image];
}
- (void)setName {
if ([[taskInfo objectForKey:MGMConverting] boolValue]) {
[name setStringValue:[taskInfo objectForKey:MGMFileName]];
} else {
[name setStringValue:[[taskInfo objectForKey:MGMFilePath] lastPathComponent]];
}
}
- (NSString *)YVTaskPath {
return [taskInfo objectForKey:MGMYVTaskPath];
}
- (BOOL)working {
return working;
}
- (BOOL)converting {
return converting;
}
- (BOOL)waitingToConvert {
return waitingToConvert;
}
- (NSView *)view {
return mainView;
}
- (NSString *)accessibilityRole {
return @"task";
}
- (NSString *)accessibilityDescription {
NSString *taskName = [[taskInfo objectForKey:MGMFilePath] lastPathComponent];
if ([[taskInfo objectForKey:MGMConverting] boolValue])
taskName = [taskInfo objectForKey:MGMFileName];
return [NSString stringWithFormat:@"%@ %@", taskName, [info stringValue]];
}
- (IBAction)stop:(id)sender {
stopped = YES;
if (working) {
if (converting || waitingToConvert) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[aTask terminate];
[aTask release];
aTask = nil;
[taskInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMConverting];
[self saveInfo];
} else {
[connectionManager cancelAll];
[taskInfo setObject:[NSNumber numberWithBool:NO] forKey:MGMConverting];
[self saveInfo];
}
[info setStringValue:@"Canceled"];
}
}
- (IBAction)reveal:(id)sender {
[[NSWorkspace sharedWorkspace] selectFile:[taskInfo objectForKey:MGMRevealPath] inFileViewerRootedAtPath:nil];
}
- (IBAction)restart:(id)sender {
stopped = NO;
startTime = [[NSDate date] timeIntervalSince1970]-[[taskInfo objectForKey:MGMTime] intValue];
if ([[taskInfo objectForKey:MGMConverting] boolValue]) {
[progress setHidden:NO];
[progress startAnimation:self];
[stop setHidden:NO];
[restart setHidden:YES];
working = YES;
if ([manager ableToConvert:self]) {
[self startConverson];
} else {
[info setStringValue:@"Waiting my turn to convert."];
waitingToConvert = YES;
}
} else {
[progress setHidden:NO];
[progress startAnimation:self];
[progress setIndeterminate:YES];
[videoFinder release];
videoFinder = [[MGMVideoFinder alloc] initWithURL:[NSURL URLWithString:[taskInfo objectForKey:MGMURL]] connectionManager:connectionManager maxQuality:[[taskInfo objectForKey:MGMMaxQualityKey] intValue] delegate:self];
}
[self setName];
}
- (void)saveInfo {
if (secCheckTimer!=nil) {
[secCheckTimer invalidate];
[secCheckTimer release];
secCheckTimer = nil;
}
working = NO;
converting = NO;
waitingToConvert = NO;
[progress setHidden:YES];
[progress stopAnimation:self];
[stop setHidden:YES];
[restart setHidden:NO];
[taskInfo setObject:[NSNumber numberWithInt:[[NSDate date] timeIntervalSince1970]-startTime] forKey:MGMTime];
[taskInfo writeToFile:[[taskInfo objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:MGMInfoPlist] atomically:YES];
}
- (void)loadFlash:(NSDictionary *)theInfo {
if ([taskInfo objectForKey:MGMConvertFormat]==nil) {
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert setMessageText:@"Video Download"];
[theAlert setInformativeText:@"YouView was unable to download the video, would you like to download the low quality version?"];
[theAlert addButtonWithTitle:@"Yes"];
[theAlert addButtonWithTitle:@"No"];
int result = [theAlert runModal];
if (result==1000) {
[videoFinder loadFlash];
}
} else {
[videoFinder loadFlash];
}
}
- (void)loadVideo:(NSDictionary *)theInfo {
NSFileManager *fileManager = [NSFileManager defaultManager];
[taskInfo setObject:[taskInfo objectForKey:MGMYVTaskPath] forKey:MGMRevealPath];
if ([[theInfo objectForKey:MGMVLVersion] isEqual:@"FLV"]) {
[taskInfo setObject:[[[taskInfo objectForKey:MGMFilePath] stringByDeletingPathExtension] stringByAppendingPathExtension:MGMFLVExt] forKey:MGMFilePath];
[self setName];
if ([taskInfo objectForKey:MGMConvertFormat]==nil) {
[taskInfo setObject:[[[taskInfo objectForKey:MGMDonePath] stringByDeletingPathExtension] stringByAppendingPathExtension:MGMFLVExt] forKey:MGMDonePath];
[taskInfo setObject:[[taskInfo objectForKey:MGMDonePath] lastPathComponent] forKey:MGMFileName];
NSString *lastPath = [taskInfo objectForKey:MGMYVTaskPath];
[taskInfo setObject:[[taskInfo objectForKey:MGMDonePath] stringByAppendingPathExtension:MGMYVTaskExt] forKey:MGMYVTaskPath];
if ([[taskInfo objectForKey:MGMDonePath] isEqual:[[taskInfo objectForKey:MGMFilePath] stringByDeletingLastPathComponent]]) {
[taskInfo setObject:[[taskInfo objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:[[taskInfo objectForKey:MGMFilePath] lastPathComponent]] forKey:MGMFilePath];
}
[fileManager moveItemAtPath:lastPath toPath:[taskInfo objectForKey:MGMYVTaskPath]];
}
}
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:[NSURLRequest requestWithURL:[theInfo objectForKey:MGMVLVideoURLKey]] delegate:self];
[handler setFile:[taskInfo objectForKey:MGMFilePath]];
[handler setBytesReceived:@selector(fileDownload:receivedBytes:totalBytes:expectedBytes:)];
[handler setReceiveResponse:@selector(fileDownload:didReceiveResponse:)];
[handler setFailWithError:@selector(fileDownload:didFailWithError:)];
[handler setFinish:@selector(fileDownloadDidFinish:)];
[connectionManager addHandler:handler];
[progress setHidden:NO];
[progress stopAnimation:self];
[progress setIndeterminate:NO];
[progress setDoubleValue:0];
[restart setHidden:YES];
[stop setHidden:NO];
working = YES;
[receivedSec release];
receivedSec = [@"0 Bytes" retain];
bytesReceivedSec = 1;
receivedContentLength = 0;
expectedContentLength = 0;
if (secCheckTimer==nil) {
secCheckTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(secCheck) userInfo:nil repeats:YES] retain];
}
}
- (NSString *)bytesToString:(double)bytes {
NSString *type = @"Bytes";
if (bytes>1024.00) {
type = @"KB";
bytes = bytes/1024.00;
if (bytes>1024.00) {
type = @"MB";
bytes = bytes/1024.00;
if (bytes>1024.00) {
type = @"GB";
bytes = bytes/1024.00;
}
}
}
return [NSString stringWithFormat:@"%.2f %@", bytes, type];
}
- (NSString *)secsToString:(int)secs {
NSString *type = @"Second";
if (secs>60) {
type = @"Minute";
secs = secs/60;
if (secs>60) {
type = @"Hour";
secs = secs/60;
if (secs>24) {
type = @"Day";
secs = secs/24;
}
}
}
return [NSString stringWithFormat:@"%d %@%@", secs, type, (secs==1 ? @"" : @"s")];
}
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)didFinish {
if (didFinish)
[sound release];
}
- (void)convertProcessFinish:(NSNotification *)note {
if (!stopped) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[aTask release];
aTask = nil;
[taskPipe release];
taskPipe = nil;
working = NO;
converting = NO;
[[NSFileManager defaultManager] moveItemAtPath:[taskInfo objectForKey:MGMConvertPath] toPath:[taskInfo objectForKey:MGMDonePath]];
[[NSFileManager defaultManager] removeItemAtPath:[taskInfo objectForKey:MGMYVTaskPath]];
[taskInfo setObject:[taskInfo objectForKey:MGMDonePath] forKey:MGMRevealPath];
int runTime = [[NSDate date] timeIntervalSince1970]-startTime;
[info setStringValue:[NSString stringWithFormat:@"Finished Task in %@", [self secsToString:runTime]]];
[progress setHidden:YES];
[progress stopAnimation:self];
[stop setHidden:YES];
NSSound *done = [[NSSound soundNamed:@"Glass"] retain];
[done setDelegate:self];
[done play];
[manager nextConversion];
}
}
- (void)convertProcessResponse:(NSString*)response {
if ([response hasPrefix:@"frame="]) {
NSRange f, l;
NSString *s;
int frame=0, fps=0;
f = [response rangeOfString:@"frame="];
if (f.location != NSNotFound) {
s = [response substringFromIndex:f.location + f.length];
l = [s rangeOfString:@"fps"];
if (l.location == NSNotFound) MGMLog(@"failed");
frame = [[s substringWithRange:NSMakeRange(0, l.location)] intValue];
}
f = [response rangeOfString:@"fps="];
if (f.location != NSNotFound) {
s = [response substringFromIndex:f.location + f.length];
l = [s rangeOfString:@"q"];
if (l.location == NSNotFound) MGMLog(@"failed");
fps = [[s substringWithRange:NSMakeRange(0, l.location)] intValue];
if (fps==0) {
fps = frame;
}
}
int totalFrames = videoPlayTime * videoFrameRate;
[progress setDoubleValue:(double)frame / (double)totalFrames];
int timeLeft = 0;
if (frame!=0 && fps!=0)
timeLeft = (totalFrames-frame)/fps;
[info setStringValue:[NSString stringWithFormat:@"%d FPS current frame %d - %@", fps, frame, [self secsToString:timeLeft]]];
} else if ([response hasPrefix:@"size"]) {
NSRange f, l;
NSString *s, *bitrate = nil;
double lasttime = time;
f = [response rangeOfString:@"time="];
if (f.location != NSNotFound) {
s = [response substringFromIndex:f.location + f.length];
l = [s rangeOfString:@"bitrate"];
if (l.location == NSNotFound) MGMLog(@"failed");
time = [[s substringWithRange:NSMakeRange(0, l.location)] doubleValue];
}
f = [response rangeOfString:@"bitrate="];
if (f.location != NSNotFound) {
bitrate = [[[response substringFromIndex:f.location + f.length] replace:@"\r" with:@""] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
[progress setDoubleValue:time / videoPlayTime];
int timeLeft = (videoPlayTime-time)/(time-lasttime);
if (bitrate!=nil)
[info setStringValue:[NSString stringWithFormat:@"Bitrate %@ - %@", bitrate, [self secsToString:timeLeft]]];
} else {
if ([response length] > 0)
MGMLog(@"Task: %@", response);
}
}
- (void)convertProcessRead:(NSNotification *)note {
if (![[note name] isEqual:NSFileHandleReadCompletionNotification])
return;
NSData *data = [[note userInfo] objectForKey:NSFileHandleNotificationDataItem];
if ([data length]) {
NSMutableString *buffer = [NSMutableString string];
NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSArray *components = [string componentsSeparatedByString:@"\n"];
assert([components count] > 0);
for (int i = 0; i < [components count]-1; ++i) {
[buffer appendString:[components objectAtIndex:i]];
[self convertProcessResponse:buffer];
[buffer setString: @""];
}
if ([string hasSuffix:@"\n"] || [string hasSuffix:@"\r"]) {
[buffer appendString:[components objectAtIndex:[components count]-1]];
[self convertProcessResponse:buffer];
[buffer setString:@""];
}
else {
[buffer setString:[components objectAtIndex:[components count]-1]];
}
[[note object] readInBackgroundAndNotify];
}
}
- (void)startConverson {
converting = YES;
waitingToConvert = NO;
[taskInfo setObject:[NSNumber numberWithBool:YES] forKey:MGMConverting];
NSString *file = [[self YVTaskPath] stringByAppendingPathComponent:[[[taskInfo objectForKey:MGMFilePath] lastPathComponent] stringByDeletingPathExtension]];
[taskInfo setObject:[[file stringByAppendingPathExtension:@"tmp"] stringByAppendingPathExtension:[[[manager formats] objectAtIndex:[[taskInfo objectForKey:MGMConvertFormat] intValue]] objectForKey:MGMFExtension]] forKey:MGMConvertPath];
[self setName];
NSTask *task = [[NSTask new] autorelease];
[task setLaunchPath:[[NSBundle mainBundle] pathForResource:@"mediainfo" ofType:@""]];
[task setArguments:[NSArray arrayWithObjects:[@"--Inform=file://" stringByAppendingString:[[NSBundle mainBundle] pathForResource:@"mediainfo" ofType:@"form"]], [taskInfo objectForKey:MGMFilePath], nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:[pipe fileHandleForWriting]];
[task launch];
[task waitUntilExit];
NSString *error = nil;
NSMutableData *plistData = [NSMutableData data];
[plistData appendData:[@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\r\n<plist version=\"1.0\">\r\n<array>\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[plistData appendData:[[pipe fileHandleForReading] availableData]];
[plistData appendData:[@"\r\n</array>\r\n</plist>" dataUsingEncoding:NSUTF8StringEncoding]];
NSArray *plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:&error];
if (error!=nil) {
MGMLog(@"Error %@", error);
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert addButtonWithTitle:@"OK"];
[theAlert setMessageText:@"Convert Error"];
[theAlert setInformativeText:error];
[theAlert setAlertStyle:NSWarningAlertStyle];
[theAlert runModal];
} else {
[taskInfo setObject:plist forKey:MGMMediaInfoKey];
if ([taskInfo objectForKey:MGMPreviewURL]==nil) {
int playTime = 0;
NSSize originalSize = NSZeroSize;
for (int i=0; i<[[taskInfo objectForKey:MGMMediaInfoKey] count]; i++) {
if ([[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMTypeKey] isEqual:MGMTypeGeneralKey]) {
playTime = [[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMPlayTimeKey] intValue]/1000;
} else if ([[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMTypeKey] isEqual:MGMTypeVideoKey]) {
originalSize.width = [[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMWidthKey] intValue];
originalSize.height = [[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMHeightKey] intValue];
}
}
if (!NSEqualSizes(originalSize, NSZeroSize)) {
NSTask *task = [[NSTask new] autorelease];
[task setLaunchPath:[[NSBundle mainBundle] pathForResource:@"ffmpeg" ofType:@""]];
if (playTime>8)
playTime = 8;
NSSize destSize = NSMakeSize(128, 128);
float scaleFactor = 0.0;
float scaledWidth = destSize.width;
float scaledHeight = destSize.height;
if (NSEqualSizes(originalSize, destSize) == NO) {
float widthFactor = destSize.width / originalSize.width;
float heightFactor = destSize.height / originalSize.height;
if (widthFactor < heightFactor)
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = (int)(originalSize.width * scaleFactor);
scaledHeight = (int)(originalSize.height * scaleFactor);
if ((scaledWidth/2.0)!=(float)((int)(scaledWidth/2.0)))
scaledWidth -= 1;
if ((scaledHeight/2.0)!=(float)((int)(scaledHeight/2.0)))
scaledHeight -= 1;
}
srandomdev();
NSString *savePath = [[[MGMUser cachePath] stringByAppendingPathComponent:[[[NSNumber numberWithInt:random()] stringValue] MD5]] stringByAppendingPathExtension:MGMJPGExt];
[task setArguments:[NSArray arrayWithObjects:@"-y", @"-i", [taskInfo objectForKey:MGMFilePath], @"-f", @"image2", @"-ss", [[NSNumber numberWithInt:playTime] stringValue], @"-sameq", @"-t", @"0.001", @"-s", [NSString stringWithFormat:@"%.0fx%.0f", scaledWidth, scaledHeight], savePath, nil]];
[task launch];
[task waitUntilExit];
if ([task terminationStatus]==0) {
[taskInfo setObject:[[NSURL fileURLWithPath:savePath] absoluteString] forKey:MGMPreviewURL];
NSImage *image = [[[NSImage alloc] initWithContentsOfFile:savePath] autorelease];
[icon setImage:image];
}
}
}
[taskInfo setObject:[NSNumber numberWithInt:[[NSDate date] timeIntervalSince1970]-startTime] forKey:MGMTime];
[taskInfo writeToFile:[[taskInfo objectForKey:MGMYVTaskPath] stringByAppendingPathComponent:MGMInfoPlist] atomically:YES];
aTask = [NSTask new];
[aTask setLaunchPath:[[NSBundle mainBundle] pathForResource:@"ffmpeg" ofType:@""]];
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"-y", @"-i", [taskInfo objectForKey:MGMFilePath], nil];
[arguments addObjectsFromArray:[[[manager formats] objectAtIndex:[[taskInfo objectForKey:MGMConvertFormat] intValue]] objectForKey:MGMFArguments]];
int currFormat = [[taskInfo objectForKey:MGMConvertFormat] intValue];
#if youviewdebug
MGMLog(@"Format: %d", currFormat);
#endif
if ([taskInfo objectForKey:MGMCustomBitrateKey]!=nil)
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-b", [taskInfo objectForKey:MGMCustomBitrateKey], nil]];
if (currFormat!=2 && currFormat!=3 && currFormat!=5 && currFormat!=8)
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-threads", [NSString stringWithFormat:@"%d", [[MGMSystemInfo info] CPUCount]], nil]];
for (int i=0; i<[[taskInfo objectForKey:MGMMediaInfoKey] count]; i++) {
if ([[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMTypeKey] isEqual:MGMTypeGeneralKey]) {
videoPlayTime = [[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMPlayTimeKey] doubleValue]/1000.0;
break;
}
}
if (![[taskInfo objectForKey:MGMFAudio] boolValue]) {
for (int i=0; i<[[taskInfo objectForKey:MGMMediaInfoKey] count]; i++) {
if ([[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMTypeKey] isEqual:MGMTypeVideoKey]) {
videoFrameRate = [[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMFrameRateKey] doubleValue];
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-r", [[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMFrameRateKey], nil]];
break;
}
}
}
for (int i=0; i<[[taskInfo objectForKey:MGMMediaInfoKey] count]; i++) {
if ([[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMTypeKey] isEqual:MGMTypeAudioKey]) {
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-ar", [[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMSamplingRateKey], @"-ab", [[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMBitrateKey], nil]];
break;
}
}
if ([taskInfo objectForKey:MGMCustomWidthKey]!=nil && [taskInfo objectForKey:MGMCustomHeightKey]!=nil) {
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-s", [NSString stringWithFormat:@"%@x%@", [taskInfo objectForKey:MGMCustomWidthKey], [taskInfo objectForKey:MGMCustomHeightKey]], nil]];
} else if ([taskInfo objectForKey:MGMCustomWidthKey]!=nil) {
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-s", [NSString stringWithFormat:@"%@x%@", [taskInfo objectForKey:MGMCustomWidthKey], [taskInfo objectForKey:MGMHeightKey]], nil]];
} else if ([taskInfo objectForKey:MGMCustomHeightKey]!=nil) {
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-s", [NSString stringWithFormat:@"%@x%@", [taskInfo objectForKey:MGMWidthKey], [taskInfo objectForKey:MGMCustomHeightKey]], nil]];
} else if ([taskInfo objectForKey:MGMCustomBitrateKey]==nil) {
for (int i=0; i<[[taskInfo objectForKey:MGMMediaInfoKey] count]; i++) {
if ([[[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMTypeKey] isEqual:MGMTypeVideoKey]) {
[arguments addObjectsFromArray:[NSArray arrayWithObjects:@"-b", [[[taskInfo objectForKey:MGMMediaInfoKey] objectAtIndex:i] objectForKey:MGMBitrateKey], nil]];
break;
}
}
}
[arguments addObject:[taskInfo objectForKey:MGMConvertPath]];
#if youviewdebug
NSLog(@"Task Info: %@", taskInfo);
NSLog(@"Arugments: %@", arguments);
#endif
[aTask setArguments:arguments];
taskPipe = [NSPipe new];
[aTask setStandardError:[taskPipe fileHandleForWriting]];
[aTask setStandardOutput:[taskPipe fileHandleForWriting]];
int runTime = [[NSDate date] timeIntervalSince1970]-startTime;
[taskInfo setObject:[NSNumber numberWithInt:runTime] forKey:MGMTime];
[info setStringValue:[NSString stringWithFormat:@"%@ downloaded at %@/sec and took %@", [self bytesToString:receivedContentLength], receivedSec, [self secsToString:runTime]]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(convertProcessFinish:) name:NSTaskDidTerminateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(convertProcessRead:) name:NSFileHandleReadCompletionNotification object:[taskPipe fileHandleForReading]];
[[taskPipe fileHandleForReading] readInBackgroundAndNotify];
[aTask launch];
}
}
- (void)setDownloading:(BOOL)isDownloading {
if (working != isDownloading) {
working = isDownloading;
[secCheckTimer invalidate];
[secCheckTimer release];
secCheckTimer = nil;
if (!working) {
if ([taskInfo objectForKey:MGMConvertFormat]!=nil) {
working = YES;
if ([manager ableToConvert:self]) {
[self startConverson];
} else {
[info setStringValue:@"Waiting my turn to convert."];
waitingToConvert = YES;
}
} else {
[[NSFileManager defaultManager] moveItemAtPath:[taskInfo objectForKey:MGMFilePath] toPath:[taskInfo objectForKey:MGMDonePath]];
[[NSFileManager defaultManager] removeItemAtPath:[taskInfo objectForKey:MGMYVTaskPath]];
[taskInfo setObject:[taskInfo objectForKey:MGMDonePath] forKey:MGMRevealPath];
int runTime = [[NSDate date] timeIntervalSince1970]-startTime;
[info setStringValue:[NSString stringWithFormat:@"%@ downloaded at %@/sec and took %@", [self bytesToString:receivedContentLength], receivedSec, [self secsToString:runTime]]];
[progress setHidden:YES];
[progress stopAnimation:self];
[stop setHidden:YES];
NSSound *done = [[NSSound soundNamed:@"Glass"] retain];
[done setDelegate:self];
[done play];
}
}
}
}
- (void)secCheck {
[receivedSec release];
receivedSec = [[self bytesToString:(double)bytesReceived] retain];
bytesReceivedSec = (bytesReceived==0 ? 1 : bytesReceived);
bytesReceived = 0;
int secs = (expectedContentLength-receivedContentLength)/bytesReceivedSec;
[info setStringValue:[NSString stringWithFormat:@"%@ of %@ (%@/sec) - %@", [self bytesToString:(double)receivedContentLength], [self bytesToString:(double)expectedContentLength], receivedSec, [self secsToString:secs]]];
}
- (void)fileDownload:(MGMURLBasicHandler *)theHandler didReceiveResponse:(NSHTTPURLResponse *)theResponse {
//NSLog(@"Got response %d", [theResponse statusCode]);
[self setDownloading:YES];
}
- (void)fileDownload:(MGMURLBasicHandler *)theHandler receivedBytes:(unsigned long)theBytes totalBytes:(unsigned long)theTotalBytes expectedBytes:(unsigned long)theExpectedBytes {
expectedContentLength = theExpectedBytes;
receivedContentLength = theTotalBytes;
bytesReceived += theBytes;
[progress setDoubleValue:(double)theTotalBytes/(double)theExpectedBytes];
}
- (void)fileDownload:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)error {
NSLog(@"%@", error);
[self saveInfo];
if ([[videoFinder version] isEqual:@"FLV"]) {
[info setStringValue:@"Error"];
NSAlert *theAlert = [[NSAlert new] autorelease];
[theAlert addButtonWithTitle:@"OK"];
[theAlert setMessageText:@"Video Downloading"];
[theAlert setInformativeText:@"YouView was unable to download the video.\nPlease contact support via the help menu."];
[theAlert runModal];
} else {
[videoFinder shouldLoadFlash];
}
}
- (void)fileDownloadDidFinish:(MGMURLBasicHandler *)theHandler {
[self setDownloading:NO];
}
@end

View File

@ -0,0 +1,22 @@
//
// MGMGradient.h
// YouView
//
// Created by Mr. Gecko on 1/28/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MGMGradient : NSOutlineView {
}
@end
@interface MGMTextCell : NSTextFieldCell {
}
- (NSString*)truncateString:(NSString *)string forWidth:(double) inWidth andAttributes:(NSDictionary*)inAttributes;
@end

View File

@ -0,0 +1,135 @@
//
// MGMGradient.m
// YouView
//
// Created by Mr. Gecko on 1/28/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMGradient.h"
#import "MGMController.h"
#import <GeckoReporter/GeckoReporter.h>
@implementation MGMGradient
- (void)awakeFromNib {
[self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
NSTableColumn *column = [[self tableColumns] objectAtIndex:0];
MGMTextCell *theTextCell = [[MGMTextCell new] autorelease];
[column setDataCell:theTextCell];
[[column dataCell] setFont:[NSFont labelFontOfSize:[NSFont labelFontSize]]];
}
- (void)dealloc {
#if releaseDebug
MGMLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)highlightSelectionInClipRect:(NSRect)clipRect {
int selectedRow = [self selectedRow];
if(selectedRow == -1)
return;
[self lockFocus];
NSImage *bgImg;
if([[self window] firstResponder]==self && [[self window] isKeyWindow]) {
bgImg = [NSImage imageNamed:@"gradient"];
} else {
bgImg = [NSImage imageNamed:@"gradientDeselected"];
}
NSRect drawingRect = [self rectOfRow:selectedRow];
NSSize bgSize = [bgImg size];
int i = 0;
for (i = drawingRect.origin.x; i < (drawingRect.origin.x + drawingRect.size.width); i += bgSize.width) {
[bgImg drawInRect:NSMakeRect(i, drawingRect.origin.y, bgSize.width, drawingRect.size.height)
fromRect:NSMakeRect(0, 0, bgSize.width, bgSize.height)
operation:NSCompositeSourceOver
fraction:1.0];
}
[self unlockFocus];
}
- (void)viewWillDraw {
if ([[self window] isKeyWindow]) {
[self setBackgroundColor:[NSColor colorWithCalibratedRed:0.863389 green:0.892058 blue:0.9205 alpha:1.0]];
} else {
[self setBackgroundColor:[NSColor colorWithCalibratedRed:0.929412 green:0.929412 blue:0.929412 alpha:1.0]];
}
}
@end
@implementation MGMTextCell
- (id)init {
self = [super init];
if (self != nil) {
[self setWraps:NO];
}
return self;
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
[controlView lockFocus];
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithDictionary:[[self attributedStringValue] attributesAtIndex:0 effectiveRange:NULL]];
cellFrame.size.width += 10;
if ([self isHighlighted]) {
[attrs setObject:[NSFont boldSystemFontOfSize:[[self font] pointSize]] forKey:NSFontAttributeName];
[attrs setValue:[NSColor whiteColor] forKey:@"NSColor"];
} else {
[attrs setObject:[self font] forKey:NSFontAttributeName];
}
NSRect inset = [self drawingRectForBounds:cellFrame];
inset.origin.x += 4;
inset.size.width-=inset.origin.x;
NSString *displayString = [self truncateString:[self stringValue] forWidth:inset.size.width andAttributes:attrs];
[displayString drawAtPoint:inset.origin withAttributes:attrs];
[controlView unlockFocus];
}
- (NSString*)truncateString:(NSString *)string forWidth:(double) inWidth andAttributes:(NSDictionary*)inAttributes {
unichar ellipsesCharacter = 0x2026;
NSString* ellipsisString = [NSString stringWithCharacters:&ellipsesCharacter length:1];
NSString* truncatedString = [NSString stringWithString:string];
int truncatedStringLength = [truncatedString length];
if ((truncatedStringLength > 2) && ([truncatedString sizeWithAttributes:inAttributes].width > inWidth)) {
double targetWidth = inWidth - [ellipsisString sizeWithAttributes:inAttributes].width;
NSCharacterSet* whiteSpaceCharacters = [NSCharacterSet
whitespaceAndNewlineCharacterSet];
while([truncatedString sizeWithAttributes:inAttributes].width > targetWidth && truncatedStringLength) {
truncatedStringLength--;
while ([whiteSpaceCharacters characterIsMember:[truncatedString characterAtIndex:(truncatedStringLength -1)]]) {
truncatedStringLength--;
}
truncatedString = [truncatedString substringToIndex:truncatedStringLength];
}
truncatedString = [truncatedString stringByAppendingString:ellipsisString];
}
return truncatedString;
}
- (NSRect)drawingRectForBounds:(NSRect)theRect {
NSRect newRect = [super drawingRectForBounds:theRect];
NSSize textSize = [self cellSizeForBounds:theRect];
float heightDelta = newRect.size.height - textSize.height;
if (heightDelta > 0) {
newRect.size.height -= heightDelta;
newRect.origin.y += (heightDelta / 2);
}
newRect.size.width -= 1;
return newRect;
}
@end

View File

@ -0,0 +1,15 @@
//
// splitView.h
// YouView
//
// Created by Mr. Gecko on 1/23/09.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. https://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface MGMSplitView : NSSplitView {
}
@end

View File

@ -0,0 +1,19 @@
//
// splitView.m
// YouView
//
// Created by Mr. Gecko on 1/23/09.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. https://mrgeckosmedia.com/
//
#import "MGMSplitView.h"
@implementation MGMSplitView
- (CGFloat)dividerThickness {
return 1.0;
}
- (void)drawDividerInRect:(NSRect)aRect {
[[NSColor lightGrayColor] set];
NSRectFill (aRect);
}
@end

View File

@ -0,0 +1,21 @@
//
// MGMViewCell.h
// YouView
//
// Created by Mr. Gecko on 4/15/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import <Cocoa/Cocoa.h>
@protocol MGMViewCellController <NSObject>
- (NSView *)view;
- (NSString *)accessibilityDescription;
- (NSString *)accessibilityRole;
@end
@interface MGMViewCell : NSCell {
NSObject<MGMViewCellController> *subview;
}
- (void)addSubview:(NSObject<MGMViewCellController> *)view;
@end

View File

@ -0,0 +1,68 @@
//
// MGMViewCell.m
// YouView
//
// Created by Mr. Gecko on 4/15/09.
// Copyright (c) 2015 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/ All rights reserved.
//
#import "MGMViewCell.h"
#import "MGMController.h"
#import <GeckoReporter/GeckoReporter.h>
@implementation MGMViewCell
- (void)addSubview:(NSObject<MGMViewCellController> *)view {
subview = view;
}
- (void)dealloc {
#if releaseDebug
MGMLog(@"%s Releasing", __PRETTY_FUNCTION__);
#endif
subview = nil;
[super dealloc];
}
- (NSView *)view {
return [subview view];
}
- (NSArray *)accessibilityAttributeNames {
NSMutableArray *names = [[[super accessibilityAttributeNames] mutableCopy] autorelease];
[names addObject:NSAccessibilityEnabledAttribute];
[names addObject:NSAccessibilityDescriptionAttribute];
[names addObject:NSAccessibilityRoleAttribute];
return names;
}
- (id)accessibilityAttributeValue:(NSString *)attribute {
if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
if ([subview respondsToSelector:@selector(accessibilityDescription)])
return [subview accessibilityDescription];
} else if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
if ([subview respondsToSelector:@selector(accessibilityRole)])
return [subview accessibilityRole];
} else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
return [NSNumber numberWithBool:YES];
} else {
return [super accessibilityAttributeValue:attribute];
}
return @"";
}
- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute] || [attribute isEqualToString:NSAccessibilityRoleAttribute]) {
return NO;
} else {
return [super accessibilityIsAttributeSettable:attribute];
}
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
[super drawWithFrame:cellFrame inView:controlView];
[[self view] setFrame:cellFrame];
if ([[self view] superview] != controlView) {
[controlView addSubview:[self view]];
}
}
@end

View File

@ -0,0 +1,25 @@
//
// MGMXML.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLNode.h"
#import "MGMXMLElement.h"
#import "MGMXMLDocument.h"
#import "MGMXMLDTD.h"
#import "MGMXMLDTDNode.h"
#import "MGMXMLNodeOptions.h"

View File

@ -0,0 +1,32 @@
//
// MGMXMLAddons.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import <libxml/parser.h>
#import <libxml/tree.h>
@interface NSValue (MGMXMLAddons)
+ (id)valueWithXMLError:(xmlErrorPtr)error;
- (xmlErrorPtr)xmlErrorValue;
@end
@interface NSString (MGMXMLAddons)
+ (NSString *)stringWithXMLString:(const xmlChar *)xmlString;
- (const xmlChar *)xmlString;
@end

View File

@ -0,0 +1,40 @@
//
// MGMXMLAddons.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLAddons.h"
@implementation NSValue (MGMXMLAddons)
+ (id)valueWithXMLError:(xmlErrorPtr)error {
return [NSValue valueWithBytes:error objCType:@encode(xmlErrorPtr)];
}
- (xmlErrorPtr)xmlErrorValue {
xmlErrorPtr error;
[self getValue:&error];
return error;
}
@end
@implementation NSString (MGMXMLAddons)
+ (NSString *)stringWithXMLString:(const xmlChar *)xmlString {
return [[[NSString alloc] initWithBytes:(const char *)xmlString length:strlen((const char *)xmlString) encoding:NSUTF8StringEncoding] autorelease];
}
- (const xmlChar *)xmlString {
return (const xmlChar *)[self UTF8String];
}
@end

View File

@ -0,0 +1,45 @@
//
// MGMXMLDTD.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "MGMXMLNode.h"
@interface MGMXMLDTD : MGMXMLNode {
}
//- (id)initWithContentsOfURL:(NSURL *)url options:(NSUInteger)mask error:(NSError **)error;
//- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error; //primitive
//- (void)setPublicID:(NSString *)publicID; //primitive
//- (NSString *)publicID; //primitive
//- (void)setSystemID:(NSString *)systemID; //primitive
//- (NSString *)systemID; //primitive
//- (void)insertChild:(MGMXMLNode *)child atIndex:(NSUInteger)index; //primitive
//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
//- (void)removeChildAtIndex:(NSUInteger)index; //primitive
//- (void)setChildren:(NSArray *)children; //primitive
//- (void)addChild:(MGMXMLNode *)child;
//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(MGMXMLNode *)node;
//- (MGMXMLDTDNode *)entityDeclarationForName:(NSString *)name; //primitive
//- (MGMXMLDTDNode *)notationDeclarationForName:(NSString *)name; //primitive
//- (MGMXMLDTDNode *)elementDeclarationForName:(NSString *)name; //primitive
//- (MGMXMLDTDNode *)attributeDeclarationForName:(NSString *)name elementName:(NSString *)elementName; //primitive
//+ (MGMXMLDTDNode *)predefinedEntityDeclarationForName:(NSString *)name;
@end

View File

@ -0,0 +1,24 @@
//
// MGMXMLDTD.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLDTD.h"
@implementation MGMXMLDTD
@end

View File

@ -0,0 +1,36 @@
//
// MGMXMLDTDNode.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "MGMXMLNode.h"
@interface MGMXMLDTDNode : MGMXMLNode {
}
//- (id)initWithXMLString:(NSString *)string; //primitive
//- (void)setDTDKind:(MGMXMLDTDNodeKind)kind; //primitive
//- (MGMXMLDTDNodeKind)DTDKind; //primitive
//- (BOOL)isExternal; //primitive
//- (void)setPublicID:(NSString *)publicID; //primitive
//- (NSString *)publicID; //primitive
//- (void)setSystemID:(NSString *)systemID; //primitive
//- (NSString *)systemID; //primitive
//- (void)setNotationName:(NSString *)notationName; //primitive
//- (NSString *)notationName; //primitive
@end

View File

@ -0,0 +1,24 @@
//
// MGMXMLDTDNode.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLDTDNode.h"
@implementation MGMXMLDTDNode
@end

View File

@ -0,0 +1,64 @@
//
// MGMXMLDocument.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "MGMXMLNode.h"
#define MGMXMLDocPtr (xmlDocPtr)commonXML
@interface MGMXMLDocument : MGMXMLNode {
}
- (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error;
- (id)initWithContentsOfURL:(NSURL *)url options:(NSUInteger)mask error:(NSError **)error;
- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error; //primitive
- (id)initWithRootElement:(MGMXMLElement *)element;
//+ (Class)replacementClassForClass:(Class)cls;
//- (void)setCharacterEncoding:(NSString *)encoding; //primitive
//- (NSString *)characterEncoding; //primitive
//- (void)setVersion:(NSString *)version; //primitive
//- (NSString *)version; //primitive
//- (void)setStandalone:(BOOL)standalone; //primitive
//- (BOOL)isStandalone; //primitive
//- (void)setDocumentContentKind:(MGMXMLDocumentContentKind)kind; //primitive
//- (MGMXMLDocumentContentKind)documentContentKind; //primitive
//- (void)setMIMEType:(NSString *)MIMEType; //primitive
//- (NSString *)MIMEType; //primitive
//- (void)setDTD:(MGMXMLDTD *)documentTypeDeclaration; //primitive
//- (MGMXMLDTD *)DTD; //primitive
- (void)setRootElement:(MGMXMLNode *)root;
- (MGMXMLElement *)rootElement; //primitive
//- (void)insertChild:(MGMXMLNode *)child atIndex:(NSUInteger)index; //primitive
//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
//- (void)removeChildAtIndex:(NSUInteger)index; //primitive
//- (void)setChildren:(NSArray *)children; //primitive
//- (void)addChild:(MGMXMLNode *)child;
//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(MGMXMLNode *)node;
- (NSData *)XMLData;
- (NSData *)XMLDataWithOptions:(NSUInteger)options;
//- (id)objectByApplyingXSLT:(NSData *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error;
//- (id)objectByApplyingXSLTString:(NSString *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error;
//- (id)objectByApplyingXSLTAtURL:(NSURL *)xsltURL arguments:(NSDictionary *)argument error:(NSError **)error;
//- (BOOL)validateAndReturnError:(NSError **)error;
@end

View File

@ -0,0 +1,94 @@
//
// MGMXMLDocument.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLDocument.h"
#import "MGMXMLElement.h"
#import <libxml/HTMLtree.h>
#import <libxml/HTMLparser.h>
@interface MGMXMLNode (MGMPrivate)
- (void)setDocument:(MGMXMLDocument *)theDocument;
@end
@implementation MGMXMLDocument
- (id)initWithXMLString:(NSString *)string options:(NSUInteger)mask error:(NSError **)error {
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [self initWithData:data options:mask error:error];
}
- (id)initWithContentsOfURL:(NSURL *)url options:(NSUInteger)mask error:(NSError **)error {
NSData *data = [NSData dataWithContentsOfURL:url];
return [self initWithData:data options:mask error:error];
}
- (id)initWithData:(NSData *)data options:(NSUInteger)mask error:(NSError **)error {
if ((self = [super init])) {
if (data==nil || [data length]<=0) {
if (error!=nil) *error = [NSError errorWithDomain:MGMXMLErrorDomain code:0 userInfo:[NSDictionary dictionaryWithObject:@"Data has no length." forKey:NSLocalizedDescriptionKey]];
[self release];
self = nil;
} else {
xmlKeepBlanksDefault(0);
xmlDocPtr document = NULL;
if (mask & MGMXMLDocumentTidyHTML) {
document = htmlReadMemory([data bytes], [data length], NULL, NULL, XML_PARSE_RECOVER | HTML_PARSE_NONET);
} else {
document = xmlParseMemory([data bytes], [data length]);
}
if (document==NULL) {
if (error!=nil) *error = [NSError errorWithDomain:MGMXMLErrorDomain code:1 userInfo:[NSDictionary dictionaryWithObject:@"Unable to parse document." forKey:NSLocalizedDescriptionKey]];
[self release];
self = nil;
} else {
[self setTypeXMLPtr:(xmlTypPtr)document];
}
}
}
return self;
}
- (id)initWithRootElement:(MGMXMLElement *)element {
if ((self = [super init])) {
xmlDocPtr document = xmlNewDoc(NULL);
if (element!=nil) {
xmlDocSetRootElement(document, (xmlNodePtr)[element commonXML]);
[element setDocument:self];
}
[self setTypeXMLPtr:(xmlTypPtr)document];
}
return self;
}
- (void)setRootElement:(MGMXMLNode *)root {
if ([root kind]==MGMXMLNamespaceKind)
return;
xmlDocSetRootElement(MGMXMLDocPtr, (xmlNodePtr)[root commonXML]);
}
- (MGMXMLElement *)rootElement {
xmlNodePtr element = xmlDocGetRootElement(MGMXMLDocPtr);
if (element!=NULL)
return [MGMXMLElement nodeWithTypeXMLPtr:(xmlTypPtr)element];
return nil;
}
- (NSData *)XMLData {
return [[self XMLStringWithOptions:0] dataUsingEncoding:NSUTF8StringEncoding];
}
- (NSData *)XMLDataWithOptions:(NSUInteger)options {
return [[self XMLStringWithOptions:options] dataUsingEncoding:NSUTF8StringEncoding];
}
@end

View File

@ -0,0 +1,57 @@
//
// MGMXMLElement.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "MGMXMLNode.h"
@interface MGMXMLElement : MGMXMLNode {
}
- (id)initWithName:(NSString *)name;
//- (id)initWithName:(NSString *)name URI:(NSString *)URI; //primitive
- (id)initWithName:(NSString *)name stringValue:(NSString *)string;
- (id)initWithXMLString:(NSString *)string error:(NSError **)error;
- (NSArray *)elementsForName:(NSString *)name;
- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI;
- (void)addAttribute:(MGMXMLNode *)attribute; //primitive
- (void)removeAttributeForName:(NSString *)name; //primitive
//- (void)setAttributes:(NSArray *)attributes; //primitive
//- (void)setAttributesAsDictionary:(NSDictionary *)attributes;
- (NSArray *)attributes; //primitive
- (MGMXMLNode *)attributeForName:(NSString *)name;
//- (MGMXMLNode *)attributeForLocalName:(NSString *)localName URI:(NSString *)URI; //primitive
//- (void)addNamespace:(MGMXMLNode *)aNamespace; //primitive
//- (void)removeNamespaceForPrefix:(NSString *)name; //primitive
//- (void)setNamespaces:(NSArray *)namespaces; //primitive
//- (NSArray *)namespaces; //primitive
//- (MGMXMLNode *)namespaceForPrefix:(NSString *)name;
//- (MGMXMLNode *)resolveNamespaceForName:(NSString *)name;
- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI;
//- (void)insertChild:(MGMXMLNode *)child atIndex:(NSUInteger)index; //primitive
//- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index;
//- (void)removeChildAtIndex:(NSUInteger)index; //primitive
//- (void)setChildren:(NSArray *)children; //primitive
//- (void)addChild:(MGMXMLNode *)child;
//- (void)replaceChildAtIndex:(NSUInteger)index withNode:(MGMXMLNode *)node;
//- (void)normalizeAdjacentTextNodesPreservingCDATA:(BOOL)preserve;
@end

View File

@ -0,0 +1,154 @@
//
// MGMXMLElement.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLElement.h"
#import "MGMXMLDocument.h"
#import "MGMXMLAddons.h"
@implementation MGMXMLElement
- (id)initWithName:(NSString *)name {
return [self initWithName:name stringValue:nil];
}
- (id)initWithName:(NSString *)name stringValue:(NSString *)string {
if ((self = [super init])) {
xmlNodePtr node = xmlNewNode(NULL, [name xmlString]);
if (string!=nil)
xmlNodeSetContent(node, [string xmlString]);
[self setTypeXMLPtr:(xmlTypPtr)node];
}
return self;
}
- (id)initWithXMLString:(NSString *)string error:(NSError **)error {
[super release];
MGMXMLDocument *document = [[MGMXMLDocument alloc] initWithXMLString:string options:0 error:error];
MGMXMLElement *element = nil;
if (document!=nil) {
element = [[document rootElement] retain];
if (element!=nil)
[element detach];
[document release];
}
return element;
}
- (NSArray *)elementsForName:(NSString *)name URI:(NSString *)URI resolvingNamespacePrefix:(BOOL)resolveNamespacePrefix {
NSMutableArray *elements = [NSMutableArray array];
if (resolveNamespacePrefix && URI!=nil) {
NSString *prefix = [self resolvePrefixForNamespaceURI:URI];
if (prefix!=nil)
name = [NSString stringWithFormat:@"%@:%@", prefix, name];
}
NSString *localName = [[self class] localNameForName:name];
BOOL hasPrefix = ([[self class] prefixForName:localName]!=nil);
xmlNodePtr child = MGMXMLNodePtr->children;
while (child!=NULL) {
if (child->type==MGMXMLElementKind) {
BOOL shouldAddElement = NO;
if (URI==nil) {
shouldAddElement = xmlStrEqual(child->name, [name xmlString]);
} else {
if (hasPrefix && xmlStrEqual(child->name, [name xmlString]))
shouldAddElement = YES;
else if (child->ns!=NULL)
shouldAddElement = xmlStrEqual(child->name, [(hasPrefix ? localName : name) xmlString]) && xmlStrEqual(child->ns->href, [URI xmlString]);
}
if (shouldAddElement)
[elements addObject:[MGMXMLElement nodeWithTypeXMLPtr:(xmlTypPtr)child]];
}
child = child->next;
}
return elements;
}
- (NSArray *)elementsForName:(NSString *)name {
NSString *localName = [[self class] localNameForName:name];
NSString *prefix = [[self class] prefixForName:name];
NSString *uri = nil;
if (prefix!=nil) {
if (MGMXMLNodePtr->doc==NULL) {
NSLog(@"You may not search for elements with a namespace if there is no document.");
return nil;
}
xmlNsPtr namespace = xmlSearchNs(MGMXMLNodePtr->doc, MGMXMLNodePtr, [prefix xmlString]);
if (namespace!=NULL)
uri = [NSString stringWithXMLString:namespace->href];
}
return [self elementsForName:localName URI:uri resolvingNamespacePrefix:NO];
}
- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI {
return [self elementsForName:localName URI:URI resolvingNamespacePrefix:YES];
}
- (void)addAttribute:(MGMXMLNode *)attribute {
if ([attribute kind]==MGMXMLAttributeKind && [attribute commonXML]->parent!=NULL)
[self removeAttributeForName:[attribute name]];
xmlAddChild(MGMXMLNodePtr, (xmlNodePtr)[attribute commonXML]);
}
- (void)removeAttributeForName:(NSString *)name {
xmlAttrPtr attribute = MGMXMLNodePtr->properties;
while (attribute!=NULL) {
if (xmlStrEqual(attribute->name, [name xmlString])) {
[[self class] detatchAttribute:attribute fromNode:MGMXMLNodePtr];
if(attribute->_private == NULL)
xmlFreeProp(attribute);
break;
}
attribute = attribute->next;
}
}
- (NSArray *)attributes {
NSMutableArray *attributes = [NSMutableArray array];
xmlAttrPtr attribute = MGMXMLNodePtr->properties;
while (attribute!=NULL) {
[attributes addObject:[MGMXMLNode nodeWithTypeXMLPtr:(xmlTypPtr)attribute]];
attribute = attribute->next;
}
return attributes;
}
- (MGMXMLNode *)attributeForName:(NSString *)name {
xmlAttrPtr attribute = MGMXMLNodePtr->properties;
while (attribute!=NULL) {
if (xmlStrEqual(attribute->name, [name xmlString]))
return [MGMXMLNode nodeWithTypeXMLPtr:(xmlTypPtr)attribute];
attribute = attribute->next;
}
return nil;
}
- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI {
xmlNodePtr child = MGMXMLNodePtr;
while (child!=NULL) {
xmlNsPtr namespace = child->nsDef;
while (namespace!=NULL) {
if (xmlStrEqual(namespace->href, [namespaceURI xmlString])) {
if (namespace->prefix!=NULL)
return [NSString stringWithXMLString:namespace->prefix];
}
namespace = namespace->next;
}
}
return nil;
}
@end

View File

@ -0,0 +1,155 @@
//
// MGMXMLNode.h
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "MGMXMLNodeOptions.h"
#import <libxml/parser.h>
#import <libxml/tree.h>
#import <libxml/xpath.h>
#import <libxml/xpathInternals.h>
#import <libxml/HTMLtree.h>
#import <libxml/HTMLparser.h>
#define MGMXMLNodePtr ((xmlNodePtr)commonXML)
#define MGMXMLAttrPtr ((xmlAttrPtr)commonXML)
#define MGMXMLDTDPtr ((xmlDtdPtr)commonXML)
@class MGMXMLDocument, MGMXMLElement;
extern NSString * const MGMXMLErrorDomain;
typedef enum {
MGMXMLInvalidKind = 0,
MGMXMLDocumentKind = XML_DOCUMENT_NODE,
MGMXMLElementKind = XML_ELEMENT_NODE,
MGMXMLAttributeKind = XML_ATTRIBUTE_NODE,
MGMXMLNamespaceKind = XML_NAMESPACE_DECL,
MGMXMLProcessingInstructionKind = XML_PI_NODE,
MGMXMLCommentKind = XML_COMMENT_NODE,
MGMXMLTextKind = XML_TEXT_NODE,
MGMXMLDTDKind = XML_DTD_NODE,
MGMXMLEntityDeclarationKind = XML_ENTITY_DECL,
MGMXMLAttributeDeclarationKind = XML_ATTRIBUTE_DECL,
MGMXMLElementDeclarationKind = XML_ELEMENT_DECL,
MGMXMLNotationDeclarationKind = XML_NOTATION_NODE
} MGMXMLNodeKind;
//The common XML structure that has type.
typedef struct _xmlTyp xmlTyp;
typedef xmlTyp *xmlTypPtr;
struct _xmlTyp {
void *trash;
xmlElementType type;
};
//The common XML structure.
typedef struct _xmlCom xmlCom;
typedef xmlCom *xmlComPtr;
struct _xmlCom {
void *_private;
xmlElementType type;
char *name;
struct _xmlNode *children;
struct _xmlNode *last;
struct _xmlNode *parent;
struct _xmlNode *next;
struct _xmlNode *prev;
struct _xmlDoc *doc;
};
@interface MGMXMLNode : NSObject {
xmlComPtr commonXML;
xmlNsPtr namespaceXML;
xmlNodePtr parentNode;
MGMXMLNodeKind type;
MGMXMLDocument *documentNode;
}
+ (id)nodeWithTypeXMLPtr:(xmlTypPtr)theXMLPtr;
- (id)initWithTypeXMLPtr:(xmlTypPtr)theXMLPtr;
+ (void)stripDocumentFromAttribute:(xmlAttrPtr)theAttribute;
+ (void)stripDocumentFromNode:(xmlNodePtr)theNode;
+ (void)removeAttributesFromNode:(xmlNodePtr)theNode;
+ (void)removeNamespacesFromNode:(xmlNodePtr)theNode;
+ (void)removeChildrenFromNode:(xmlNodePtr)theNode;
+ (void)freeNode:(xmlNodePtr)theNode;
- (void)setTypeXMLPtr:(xmlTypPtr)theXMLPtr;
- (void)releaseDocument;
+ (BOOL)isNode:(MGMXMLNodeKind)theType;
- (BOOL)isNode;
+ (NSError *)lastError;
- (NSError *)lastError;
- (id)initWithKind:(MGMXMLNodeKind)kind;
//- (id)initWithKind:(MGMXMLNodeKind)kind options:(NSUInteger)options; //primitive
//+ (id)document;
//+ (id)documentWithRootElement:(MGMXMLElement *)element;
//+ (id)elementWithName:(NSString *)name;
//+ (id)elementWithName:(NSString *)name URI:(NSString *)URI;
//+ (id)elementWithName:(NSString *)name stringValue:(NSString *)string;
//+ (id)elementWithName:(NSString *)name children:(NSArray *)children attributes:(NSArray *)attributes;
//+ (id)attributeWithName:(NSString *)name stringValue:(NSString *)stringValue;
//+ (id)attributeWithName:(NSString *)name URI:(NSString *)URI stringValue:(NSString *)stringValue;
//+ (id)namespaceWithName:(NSString *)name stringValue:(NSString *)stringValue;
//+ (id)processingInstructionWithName:(NSString *)name stringValue:(NSString *)stringValue;
//+ (id)commentWithStringValue:(NSString *)stringValue;
//+ (id)textWithStringValue:(NSString *)stringValue;
//+ (id)DTDNodeWithXMLString:(NSString *)string;
- (MGMXMLNodeKind)kind;
- (xmlComPtr)commonXML;
- (xmlNsPtr)nameSpaceXML;
- (void)setName:(NSString *)name;
- (NSString *)name;
//- (void)setObjectValue:(id)value; //primitive
//- (id)objectValue; //primitive
- (void)setStringValue:(NSString *)string;
//- (void)setStringValue:(NSString *)string resolvingEntities:(BOOL)resolve; //primitive
- (NSString *)stringValue; //primitive
//- (NSUInteger)index; //primitive
//- (NSUInteger)level;
- (MGMXMLDocument *)rootDocument;
- (MGMXMLNode *)parent; //primitive
//- (NSUInteger)childCount; //primitive
//- (NSArray *)children; //primitive
- (MGMXMLNode *)childAtIndex:(NSUInteger)index; //primitive
//- (MGMXMLNode *)previousSibling;
//- (MGMXMLNode *)nextSibling;
//- (MGMXMLNode *)previousNode;
//- (MGMXMLNode *)nextNode;
+ (void)detatchAttribute:(xmlAttrPtr)theAttribute fromNode:(xmlNodePtr)theNode;
- (void)detach; //primitive
//- (NSString *)XPath;
//- (NSString *)localName; //primitive
//- (NSString *)prefix; //primitive
//- (void)setURI:(NSString *)URI; //primitive
//- (NSString *)URI; //primitive
+ (NSString *)localNameForName:(NSString *)name;
+ (NSString *)prefixForName:(NSString *)name;
//+ (MGMXMLNode *)predefinedNamespaceForPrefix:(NSString *)name;
- (NSString *)description;
- (NSString *)XMLString;
- (NSString *)XMLStringWithOptions:(NSUInteger)options;
//- (NSString *)canonicalXMLStringPreservingComments:(BOOL)comments;
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
//- (NSArray *)objectsForXQuery:(NSString *)xquery constants:(NSDictionary *)constants error:(NSError **)error;
//- (NSArray *)objectsForXQuery:(NSString *)xquery error:(NSError **)error;
@end

View File

@ -0,0 +1,547 @@
//
// MGMXMLNode.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "MGMXMLNode.h"
#import "MGMXMLAddons.h"
#import "MGMXMLDocument.h"
#import "MGMXMLElement.h"
#import "MGMXMLNodeOptions.h"
NSString * const MGMXMLErrorDomain = @"MGMXMLErrorDomain";
NSString * const MGMXMLLastError = @"MGMXMLLastError";
static NSMutableDictionary *MGMXMLInfo = nil;
static void MGMXMLErrorHandler(void *userData, xmlErrorPtr error) {
NSAutoreleasePool *pool = [NSAutoreleasePool new];;
if (error==NULL) {
[MGMXMLInfo removeObjectForKey:MGMXMLLastError];
} else {
[MGMXMLInfo setObject:[NSValue valueWithXMLError:error] forKey:MGMXMLLastError];
}
[pool drain];
}
@implementation MGMXMLNode
+ (void)initialize {
if (MGMXMLInfo==nil) {
MGMXMLInfo = [NSMutableDictionary new];
initGenericErrorDefaultFunc(NULL);
xmlSetStructuredErrorFunc(NULL, MGMXMLErrorHandler);
xmlKeepBlanksDefault(0);
}
}
- (id)init {
if ((self = [super init])) {
commonXML = NULL;
namespaceXML = NULL;
parentNode = NULL;
type = MGMXMLInvalidKind;
}
return self;
}
+ (id)nodeWithTypeXMLPtr:(xmlTypPtr)theXMLPtr {
return [[[self alloc] initWithTypeXMLPtr:theXMLPtr] autorelease];
}
- (id)initWithTypeXMLPtr:(xmlTypPtr)theXMLPtr {
if ((self = [self init])) {
if (theXMLPtr==NULL) {
//NSLog(@"NULL XMLPtr");
[self release];
self = nil;
} else {
if (theXMLPtr->type==MGMXMLNamespaceKind) {
xmlNsPtr xmlPtr = (xmlNsPtr)theXMLPtr;
if (xmlPtr->_private!=NULL) {
[self release];
self = nil;
return [(MGMXMLNode *)xmlPtr->_private retain];
}
} else {
xmlComPtr comXML = (xmlComPtr)theXMLPtr;
if (comXML->_private!=NULL) {
[self release];
self = nil;
return [(MGMXMLNode *)comXML->_private retain];
}
}
[self setTypeXMLPtr:theXMLPtr];
}
}
return self;
}
- (void)clearParent {
parentNode = NULL;
}
- (void)freeXML {
if (namespaceXML!=NULL) {
namespaceXML->_private = NULL;
if (parentNode==NULL)
xmlFreeNs(namespaceXML);
namespaceXML = NULL;
parentNode = NULL;
}
if (commonXML!=NULL) {
commonXML->_private = NULL;
if (type!=MGMXMLDocumentKind)
[self releaseDocument];
if (commonXML->parent==NULL) {
if (type==MGMXMLDocumentKind) {
xmlNodePtr child = commonXML->children;
while (child!=NULL) {
xmlNodePtr nextChild = child->next;
if (child->type==MGMXMLElementKind) {
if (child->prev!=NULL)
child->prev->next = child->next;
if (child->next!=NULL)
child->next->prev = child->prev;
if (commonXML->children==child)
commonXML->children = child->next;
if (commonXML->last==child)
commonXML->last = child->prev;
[[self class] freeNode:child];
}
child = nextChild;
}
xmlFreeDoc(MGMXMLDocPtr);
} else if (type==MGMXMLAttributeKind) {
xmlFreeProp(MGMXMLAttrPtr);
} else if (type==MGMXMLDTDKind) {
xmlFreeDtd(MGMXMLDTDPtr);
} else {
[[self class] freeNode:MGMXMLNodePtr];
}
}
commonXML = NULL;
}
type = MGMXMLInvalidKind;
}
- (void)dealloc {
[self freeXML];
[super dealloc];
}
+ (void)stripDocumentFromAttribute:(xmlAttrPtr)theAttribute {
xmlNodePtr child = theAttribute->children;
while (child!=NULL) {
child->doc = NULL;
child = child->next;
}
theAttribute->doc = NULL;
}
+ (void)stripDocumentFromNode:(xmlNodePtr)theNode {
xmlAttrPtr attribute = theNode->properties;
while (attribute!=NULL) {
[self stripDocumentFromAttribute:attribute];
attribute = attribute->next;
}
xmlNodePtr child = theNode->children;
while (child!=NULL) {
[self stripDocumentFromNode:child];
child = child->next;
}
theNode->doc = NULL;
}
+ (void)removeAttributesFromNode:(xmlNodePtr)theNode {
xmlAttrPtr attribute = theNode->properties;
while (attribute!=NULL) {
xmlAttrPtr nextAttribute = attribute->next;
if (attribute->_private==NULL) {
xmlFreeProp(attribute);
} else {
attribute->parent = NULL;
attribute->prev = NULL;
attribute->next = NULL;
if (attribute->doc!=NULL) [self stripDocumentFromAttribute:attribute];
}
attribute = nextAttribute;
}
theNode->properties = NULL;
}
+ (void)removeNamespacesFromNode:(xmlNodePtr)theNode {
xmlNsPtr namespace = theNode->nsDef;
while (namespace!=NULL){
xmlNsPtr nextNamespace = namespace->next;
if (namespace->_private!=NULL) {
[(MGMXMLNode *)namespace->_private clearParent];
namespace->next = NULL;
} else {
xmlFreeNs(namespace);
}
namespace = nextNamespace;
}
theNode->nsDef = NULL;
theNode->ns = NULL;
}
+ (void)removeChildrenFromNode:(xmlNodePtr)theNode {
xmlNodePtr child = theNode->children;
while (child!=NULL) {
xmlNodePtr nextChild = child->next;
[self freeNode:child];
child = nextChild;
}
theNode->children = NULL;
theNode->last = NULL;
}
+ (void)freeNode:(xmlNodePtr)theNode {
if (![[self class] isNode:theNode->type]) {
NSLog(@"Cannot free node as it is the wrong type %d.", theNode->type);
} else {
if (theNode->_private==NULL) {
[self removeAttributesFromNode:theNode];
[self removeNamespacesFromNode:theNode];
[self removeChildrenFromNode:theNode];
xmlFreeNode(theNode);
} else {
theNode->parent = NULL;
theNode->prev = NULL;
theNode->next = NULL;
if (theNode->doc!=NULL) {
[(MGMXMLNode *)theNode->_private releaseDocument];
[self stripDocumentFromNode:theNode];
}
}
}
}
- (void)setTypeXMLPtr:(xmlTypPtr)theXMLPtr {
[self freeXML];
type = theXMLPtr->type;
if (type==XML_HTML_DOCUMENT_NODE)
type = MGMXMLDocumentKind;
if (type==MGMXMLNamespaceKind) {
namespaceXML = (xmlNsPtr)theXMLPtr;
namespaceXML->_private = self;
} else {
commonXML = (xmlComPtr)theXMLPtr;
commonXML->_private = self;
if (type==MGMXMLDocumentKind && [self isMemberOfClass:[MGMXMLNode class]])
self->isa = [MGMXMLDocument class];
else if (type==MGMXMLElementKind && [self isMemberOfClass:[MGMXMLNode class]])
self->isa = [MGMXMLElement class];
if (type!=MGMXMLDocumentKind)
documentNode = [[MGMXMLDocument alloc] initWithTypeXMLPtr:(xmlTypPtr)commonXML->doc];
}
}
- (void)setDocument:(MGMXMLDocument *)theDocument {
[documentNode release];
documentNode = [theDocument retain];
}
- (void)releaseDocument {
[documentNode release];
documentNode = nil;
}
+ (BOOL)isNode:(MGMXMLNodeKind)theType {
switch (theType) {
case MGMXMLElementKind:
case MGMXMLProcessingInstructionKind:
case MGMXMLCommentKind:
case MGMXMLTextKind:
case XML_CDATA_SECTION_NODE:
return YES;
break;
default:
break;
}
return NO;
}
- (BOOL)isNode {
return [[self class] isNode:type];
}
+ (NSError *)lastError {
if ([MGMXMLInfo objectForKey:MGMXMLLastError]!=nil) {
xmlErrorPtr lastError = [[MGMXMLInfo objectForKey:MGMXMLLastError] xmlErrorValue];
NSString *description = [[NSString stringWithUTF8String:lastError->message] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [NSError errorWithDomain:MGMXMLErrorDomain code:lastError->code userInfo:[NSDictionary dictionaryWithObject:description forKey:NSLocalizedDescriptionKey]];
}
return nil;
}
- (NSError *)lastError {
return [[self class] lastError];
}
- (id)initWithKind:(MGMXMLNodeKind)kind {
if (kind==MGMXMLDocumentKind) {
[self release];
return [[MGMXMLDocument alloc] initWithRootElement:nil];
} else if (kind==MGMXMLElementKind) {
return [self initWithTypeXMLPtr:(xmlTypPtr)xmlNewNode(NULL, NULL)];
} else if (kind==MGMXMLAttributeKind) {
return [self initWithTypeXMLPtr:(xmlTypPtr)xmlNewProp(NULL, (const xmlChar *)"", NULL)];
} else if (kind==MGMXMLNamespaceKind) {
return [self initWithTypeXMLPtr:(xmlTypPtr)xmlNewNs(NULL, NULL, NULL)];
} else if (kind==MGMXMLProcessingInstructionKind) {
return [self initWithTypeXMLPtr:(xmlTypPtr)xmlNewPI(NULL, NULL)];
} else if (kind==MGMXMLCommentKind) {
return [self initWithTypeXMLPtr:(xmlTypPtr)xmlNewComment(NULL)];
} else if (kind==MGMXMLTextKind) {
return [self initWithTypeXMLPtr:(xmlTypPtr)xmlNewText(NULL)];
}
[self release];
return nil;
}
- (MGMXMLNodeKind)kind {
return type;
}
- (xmlComPtr)commonXML {
return commonXML;
}
- (xmlNsPtr)nameSpaceXML {
return namespaceXML;
}
- (void)setName:(NSString *)name {
if (type==MGMXMLNamespaceKind) {
if (namespaceXML->prefix!=NULL)
xmlFree((xmlChar *)namespaceXML->prefix);
namespaceXML->prefix = xmlStrdup([name xmlString]);
} else {
xmlNodeSetName(MGMXMLNodePtr, [name xmlString]);
}
}
- (NSString *)name {
if (type==MGMXMLNamespaceKind) {
if (namespaceXML->prefix!=NULL)
return [NSString stringWithXMLString:namespaceXML->prefix];
} else {
if (MGMXMLNodePtr->name!=NULL)
return [NSString stringWithXMLString:(xmlChar *)MGMXMLNodePtr->name];
}
return nil;
}
- (void)setStringValue:(NSString *)string {
if (type==MGMXMLNamespaceKind) {
namespaceXML->href = [string xmlString];
} else if ([self isNode] || type==MGMXMLAttributeKind) {
xmlChar *contentString = xmlEncodeEntitiesReentrant(commonXML->doc, [string xmlString]);
xmlNodeSetContent(MGMXMLNodePtr, contentString);
xmlFree(contentString);
}
}
- (NSString *)stringValue {
if (type==MGMXMLNamespaceKind) {
return [NSString stringWithXMLString:namespaceXML->href];
} else if ([self isNode] || type==MGMXMLAttributeKind) {
xmlChar *contentString = xmlNodeGetContent(MGMXMLNodePtr);
NSString *stringValue = [NSString stringWithXMLString:contentString];
xmlFree(contentString);
return stringValue;
}
return nil;
}
- (MGMXMLDocument *)rootDocument {
if (MGMXMLNodePtr->doc!=NULL)
return [MGMXMLDocument nodeWithTypeXMLPtr:(xmlTypPtr)MGMXMLNodePtr->doc];
return nil;
}
- (MGMXMLNode *)parent {
return [MGMXMLNode nodeWithTypeXMLPtr:(xmlTypPtr)MGMXMLNodePtr->parent];
}
- (MGMXMLNode *)childAtIndex:(NSUInteger)index {
if (type==MGMXMLNamespaceKind)
return nil;
NSUInteger i = 0;
xmlNodePtr child = commonXML->children;
while (child!=NULL) {
if (i==index)
return [MGMXMLNode nodeWithTypeXMLPtr:(xmlTypPtr)child];
i++;
child = child->next;
}
return nil;
}
+ (void)detatchAttribute:(xmlAttrPtr)theAttribute fromNode:(xmlNodePtr)theNode {
if (theAttribute->prev==NULL && theAttribute->next==NULL) {
theNode->properties = NULL;
} else if (theAttribute->prev==NULL) {
theNode->properties = theAttribute->next;
theAttribute->next->prev = NULL;
} else if (theAttribute->next==NULL) {
theAttribute->prev->next = NULL;
} else {
theAttribute->prev->next = theAttribute->next;
theAttribute->next->prev = theAttribute->prev;
}
theAttribute->parent = NULL;
theAttribute->prev = NULL;
theAttribute->next = NULL;
if (theAttribute->doc!=NULL) [[self class] stripDocumentFromAttribute:theAttribute];
}
- (void)detach {
if (type==MGMXMLNamespaceKind) {
if (parentNode!=NULL) {
xmlNsPtr previousNamespace = NULL;
xmlNsPtr currentNamespace = parentNode->nsDef;
while (currentNamespace!=NULL) {
if (currentNamespace==namespaceXML) {
if (previousNamespace!=NULL)
previousNamespace->next = currentNamespace->next;
else
parentNode->nsDef = currentNamespace->next;
break;
}
previousNamespace = currentNamespace;
currentNamespace = currentNamespace->next;
}
namespaceXML->next = NULL;
if (parentNode->ns==namespaceXML)
parentNode->ns = NULL;
parentNode = NULL;
}
return;
}
if (commonXML->parent==NULL) return;
if (type==MGMXMLAttributeKind) {
[[self class] detatchAttribute:MGMXMLAttrPtr fromNode:MGMXMLAttrPtr->parent];
} else if ([self isNode]) {
if (commonXML->prev==NULL && commonXML->next==NULL) {
commonXML->parent->children = NULL;
commonXML->parent->last = NULL;
} else if (commonXML->prev==NULL) {
commonXML->parent->children = commonXML->next;
commonXML->next->prev = NULL;
} else if (commonXML->next==NULL) {
commonXML->parent->last = commonXML->prev;
commonXML->prev->next = NULL;
} else {
commonXML->prev->next = commonXML->next;
commonXML->next->prev = commonXML->prev;
}
commonXML->parent = NULL;
commonXML->prev = NULL;
commonXML->next = NULL;
if (commonXML->doc!=NULL) [[self class] stripDocumentFromNode:MGMXMLNodePtr];
}
}
+ (NSString *)localNameForName:(NSString *)name {
if (name!=nil && [name length]>0) {
NSRange range = [name rangeOfString:@":"];
if (range.location!=NSNotFound)
return [name substringFromIndex:range.location+range.length];
else
return name;
}
return nil;
}
+ (NSString *)prefixForName:(NSString *)name {
if (name!=nil && [name length]>0) {
NSRange range = [name rangeOfString:@":"];
if (range.location!=NSNotFound)
return [name substringToIndex:range.location];
}
return nil;
}
- (NSString *)description {
return [self XMLString];
}
- (NSString *)XMLString {
return [self XMLStringWithOptions:0];
}
- (NSString *)XMLStringWithOptions:(NSUInteger)options {
if(options & MGMXMLNodeCompactEmptyElement)
xmlSaveNoEmptyTags = 0;
else
xmlSaveNoEmptyTags = 1;
int format = 0;
if (options & MGMXMLNodePrettyPrint) {
format = 1;
xmlIndentTreeOutput = 1;
}
xmlBufferPtr bufferPtr = xmlBufferCreate();
if (type==MGMXMLNamespaceKind)
xmlNodeDump(bufferPtr, NULL, MGMXMLNodePtr, 0, format);
else
xmlNodeDump(bufferPtr, commonXML->doc, MGMXMLNodePtr, 0, format);
NSString *result = [NSString stringWithXMLString:bufferPtr->content];
if (type!=MGMXMLTextKind)
result = [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
xmlBufferFree(bufferPtr);
return result;
}
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error {
BOOL shouldRemoveDocument = NO;
xmlDocPtr document;
if ([self isNode]) {
document = MGMXMLNodePtr->doc;
if (document==NULL) {
shouldRemoveDocument = YES;
document = xmlNewDoc(NULL);
xmlDocSetRootElement(document, MGMXMLNodePtr);
}
} else if (type==MGMXMLDocumentKind) {
document = MGMXMLDocPtr;
} else {
return nil;
}
xmlXPathContextPtr xPathContext = xmlXPathNewContext(document);
xPathContext->node = MGMXMLNodePtr;
xmlNodePtr rootNode = document->children;
if (rootNode!=NULL) {
xmlNsPtr namespace = rootNode->nsDef;
while (namespace!=NULL) {
xmlXPathRegisterNs(xPathContext, namespace->prefix, namespace->href);
namespace = namespace->next;
}
}
xmlXPathObjectPtr xPathObject = xmlXPathEvalExpression([xpath xmlString], xPathContext);
NSMutableArray *nodes = [NSMutableArray array];
if (xPathObject==NULL) {
if (error!=nil) *error = [self lastError];
nodes = nil;
} else {
int count = xmlXPathNodeSetGetLength(xPathObject->nodesetval);
if (count!=0) {
for (int i=0; i<count; i++)
[nodes addObject:[MGMXMLNode nodeWithTypeXMLPtr:(xmlTypPtr)xPathObject->nodesetval->nodeTab[i]]];
}
}
if (xPathObject) xmlXPathFreeObject(xPathObject);
if (xPathContext) xmlXPathFreeContext(xPathContext);
if (shouldRemoveDocument) {
xmlUnlinkNode(MGMXMLNodePtr);
xmlFreeDoc(document);
[[self class] stripDocumentFromNode:MGMXMLNodePtr];
}
return nodes;
}
@end

View File

@ -0,0 +1,63 @@
//
// MGMXMLNodeOptions.m
// MGMXML
//
// Created by Mr. Gecko on 9/22/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). https://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
enum {
MGMXMLNodeOptionsNone = 0,
MGMXMLNodeIsCDATA = 1 << 0,
MGMXMLNodeExpandEmptyElement = 1 << 1,
MGMXMLNodeCompactEmptyElement = 1 << 2,
MGMXMLNodeUseSingleQuotes = 1 << 3,
MGMXMLNodeUseDoubleQuotes = 1 << 4,
MGMXMLDocumentTidyHTML = 1 << 9,
MGMXMLDocumentTidyXML = 1 << 10,
MGMXMLDocumentValidate = 1 << 13,
MGMXMLDocumentXInclude = 1 << 16,
MGMXMLNodePrettyPrint = 1 << 17,
MGMXMLDocumentIncludeContentTypeDeclaration = 1 << 18,
MGMXMLNodePreserveNamespaceOrder = 1 << 20,
MGMXMLNodePreserveAttributeOrder = 1 << 21,
MGMXMLNodePreserveEntities = 1 << 22,
MGMXMLNodePreservePrefixes = 1 << 23,
MGMXMLNodePreserveCDATA = 1 << 24,
MGMXMLNodePreserveWhitespace = 1 << 25,
MGMXMLNodePreserveDTD = 1 << 26,
MGMXMLNodePreserveCharacterReferences = 1 << 27,
MGMXMLNodePreserveEmptyElements =
(MGMXMLNodeExpandEmptyElement | MGMXMLNodeCompactEmptyElement),
MGMXMLNodePreserveQuotes =
(MGMXMLNodeUseSingleQuotes | MGMXMLNodeUseDoubleQuotes),
MGMXMLNodePreserveAll = (
MGMXMLNodePreserveNamespaceOrder |
MGMXMLNodePreserveAttributeOrder |
MGMXMLNodePreserveEntities |
MGMXMLNodePreservePrefixes |
MGMXMLNodePreserveCDATA |
MGMXMLNodePreserveEmptyElements |
MGMXMLNodePreserveQuotes |
MGMXMLNodePreserveWhitespace |
MGMXMLNodePreserveDTD |
MGMXMLNodePreserveCharacterReferences |
0xFFF00000)
};

View File

@ -0,0 +1 @@
Versions/Current/GeckoReporter

View File

@ -0,0 +1 @@
Versions/Current/Headers

View File

@ -0,0 +1 @@
Versions/Current/Resources

Binary file not shown.

View File

@ -0,0 +1,12 @@
//
// GeckoReporter.h
// GeckoReporter
//
// Created by Mr. Gecko on 12/27/09.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMReporter.h"
#import "MGMSender.h"
#import "MGMSystemInfo.h"
#import "MGMLog.h"

View File

@ -0,0 +1,16 @@
//
// MGMFeedback.h
// GeckoReporter
//
// Created by Mr. Gecko on 1/2/10.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface MGMFeedback : NSObject {
}
- (IBAction)openBugReport:(id)sender;
- (IBAction)openContact:(id)sender;
@end

View File

@ -0,0 +1,12 @@
//
// MGMLog.h
// GeckoReporter
//
// Created by Mr. Gecko on 1/1/10.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
void MGMLog(NSString *format, ...);
void MGMLogv(NSString *format, va_list args);

View File

@ -0,0 +1,28 @@
//
// MGMReporter.h
// GeckoReporter
//
// Created by Mr. Gecko on 12/27/09.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMGRDoneNotification;
extern NSString * const MGMGRUserEmail;
extern NSString * const MGMGRUserName;
extern NSString * const MGMGRLastCrashDate;
extern NSString * const MGMGRSendAll;
extern NSString * const MGMGRIgnoreAll;
#define MGMGRReleaseDebug 0
@class MGMSender;
@interface MGMReporter : NSObject {
BOOL foundReport;
NSDate *lastDate;
MGMSender *mailSender;
}
+ (id)sharedReporter;
@end

View File

@ -0,0 +1,20 @@
//
// MGMSender.h
// GeckoReporter
//
// Created by Mr. Gecko on 12/28/09.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import "MGMSenderDelegate.h"
@interface MGMSender : NSObject {
id<MGMSenderDelegate> delegate;
NSMutableData *receivedData;
NSURLConnection *theConnection;
}
- (void)sendReport:(NSString *)theReportPath reportDate:(NSDate *)theReportDate userReport:(NSString *)theUserReport delegate:(id)theDelegate;
- (void)sendBug:(NSString *)theBug reproduce:(NSString *)theReproduce delegate:(id)theDelegate;
- (void)sendMessage:(NSString *)theMessage subject:(NSString *)theSubject delegate:(id)theDelegate;
@end

View File

@ -0,0 +1,15 @@
//
// MGMSenderDelegate.h
// GeckoReporter
//
// Created by Mr. Gecko on 1/2/10.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@protocol MGMSenderDelegate <NSObject>
- (void)sendError:(NSError *)error;
- (void)sendFinished:(NSString *)received;
@end

View File

@ -0,0 +1,46 @@
//
// MGMSystemInfo.h
// GeckoReporter
//
// Created by Mr. Gecko on 12/31/09.
// Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface MGMSystemInfo : NSObject {
}
+ (MGMSystemInfo *)info;
- (NSString *)architecture;
- (BOOL)is64Bit;
- (NSString *)CPUFamily;
- (int)CPUCount;
- (NSString *)model;
- (NSString *)modelName;
- (int)CPUMHz;
- (int)RAMSize;
- (int)OSMajorVersion;
- (int)OSMinorVersion;
- (int)OSBugFixVersion;
- (NSString *)OSVersion;
- (NSString *)OSVersionName;
- (BOOL)isAfterCheetah;
- (BOOL)isAfterPuma;
- (BOOL)isAfterJaguar;
- (BOOL)isAfterPanther;
- (BOOL)isAfterTiger;
- (BOOL)isAfterLeopard;
- (BOOL)isAfterSnowLeopard;
- (NSString *)language;
- (NSString *)applicationIdentifier;
- (NSString *)applicationName;
- (NSString *)applicationEXECName;
- (NSString *)applicationVersion;
- (BOOL)isUIElement;
- (NSBundle *)frameworkBundle;
- (NSString *)frameworkVersion;
- (NSString *)useragentWithApplicationNameAndVersion:(NSString *)nameAndVersion;
- (NSString *)useragent;
@end

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>GeckoReporter</string>
<key>CFBundleIdentifier</key>
<string>com.MrGeckosMedia.GeckoReporter</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>GeckoReporter</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/</string>
</dict>
</plist>

View File

@ -0,0 +1,27 @@
Copyright (c) 2010 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
Permission is granted, to any person obtaining a copy of this framework, to
use, copy, modify, merge, or redistribute this framework under the following terms:
1. This file must be included in all copies of this framework unmodified in
GeckoReporter.framework/Resource/License.txt and/or GeckoReporter.framework/Versions/A/Resources/License.txt.
2. THIS FRAMEWORK IS PROVIDED "AS IS" BY JAMES COLEMAN, WITHOUT WARRANTY OF
ANY KIND. IF YOUR SOFTWARE/FRAMEWORK/COMPUTER CRASH OR FAILS TO WORK IN ANY
WAY SHAPE OR FORM BECAUSE OF THIS FRAMEWORK, I (JAMES COLEMAN) AM NOT IN ANYWAY
RESPONSIBLE FOR YOUR PROBLEM. BUT, I MAY BE WILLING TO HELP YOU BUT NO PROMISES.
3. Redistributions of source code included in this framework must retain the
copyright notice above this license file without modifications.
4. Redistributions of binary must contain the copyright above this license file
without modifications.
5. If you use the crash reporter in this framework, you are allowed to remove the
NSTextField that says, "GeckoReporter by Mr. Gecko's Media".
6. For the users convenience, you must retain the notice about anonymous system
information being sent.
7. Mr. Gecko's Media (James Coleman) is allowed to modify these terms without notice to you
or your customers.

View File

@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ADP2,1</key>
<string>Developer Transition Kit</string>
<key>iMac1,1</key>
<string>iMac G3 (Rev A-D)</string>
<key>PowerMac2,1</key>
<string>iMac G3 (Slot-loading CD-ROM)</string>
<key>PowerMac2,2</key>
<string>iMac G3 (Summer 2000)</string>
<key>PowerMac4,1</key>
<string>iMac G3 (2001)</string>
<key>PowerMac4,2</key>
<string>iMac G4 (Flat Panel)</string>
<key>PowerMac4,5</key>
<string>iMac G4 (17&quot; Flat Panel)</string>
<key>PowerMac6,1</key>
<string>iMac G4 (USB 2.0)</string>
<key>PowerMac6,3</key>
<string>iMac G4 (20&quot; Flat Panel)</string>
<key>PowerMac8,1</key>
<string>iMac G5</string>
<key>PowerMac8,2</key>
<string>iMac G5 (Ambient Light Sensor)</string>
<key>PowerMac12,1</key>
<string>iMac G5 (iSight)</string>
<key>iMac4,1</key>
<string>iMac (Core Duo)</string>
<key>iMac4,2</key>
<string>iMac for Education (17&quot; Core Duo)</string>
<key>iMac5,1</key>
<string>iMac (Core 2 Duo 17&quot;/20&quot; SuperDrive)</string>
<key>iMac5,2</key>
<string>iMac (Core 2 Duo 17&quot; Combo Drive)</string>
<key>iMac6,1</key>
<string>iMac (Core 2 Duo 24&quot; SuperDrive)</string>
<key>iMac7,1</key>
<string>iMac (AI)</string>
<key>iMac8,1</key>
<string>iMac (2008)</string>
<key>iMac9,1</key>
<string>iMac (2009)</string>
<key>iMac10,1</key>
<string>iMac (2009 Magic)</string>
<key>iMac11,1</key>
<string>iMac (2009 Core I5)</string>
<key>PowerMac4,4</key>
<string>eMac</string>
<key>PowerMac6,4</key>
<string>eMac (USB 2.0 2005)</string>
<key>PowerMac10,1</key>
<string>Mac Mini G4</string>
<key>PowerMac10,2</key>
<string>Mac Mini (2005)</string>
<key>Macmini1,1</key>
<string>Mac Mini (Core Solo/Duo)</string>
<key>Macmini2,1</key>
<string>Mac Mini (Core 2 Duo)</string>
<key>Macmini3,1</key>
<string>Mac Mini (2009)</string>
<key>PowerBook2,1</key>
<string>iBook G3</string>
<key>PowerBook2,2</key>
<string>iBook G3 (FireWire)</string>
<key>PowerBook2,3</key>
<string>iBook G3</string>
<key>PowerBook2,4</key>
<string>iBook G3</string>
<key>PowerBook4,1</key>
<string>iBook G3 (Dual USB 2001)</string>
<key>PowerBook4,2</key>
<string>iBook G3 (16MB VRAM)</string>
<key>PowerBook4,3</key>
<string>iBook G3 Opaque 16MB VRAM/32MB VRAM 2003)</string>
<key>PowerBook6,3</key>
<string>iBook G4</string>
<key>PowerBook6,5</key>
<string>iBook G4 (2004)</string>
<key>PowerBook6,7</key>
<string>iBook G4 (Mid 2005)</string>
<key>PowerBook1,1</key>
<string>PowerBook G3</string>
<key>PowerBook3,1</key>
<string>PowerBook G3 (FireWire)</string>
<key>PowerBook3,2</key>
<string>PowerBook G4</string>
<key>PowerBook3,3</key>
<string>PowerBook G4 (Gigabit Ethernet)</string>
<key>PowerBook3,4</key>
<string>PowerBook G4 (DVI)</string>
<key>PowerBook3,5</key>
<string>PowerBook G4 (1GHz/867MHz)</string>
<key>PowerBook5,1</key>
<string>PowerBook G4 (17&quot;)</string>
<key>PowerBook5,2</key>
<string>PowerBook G4 (15&quot; FW 800)</string>
<key>PowerBook5,3</key>
<string>PowerBook G4 (17&quot; 1.33GHz)</string>
<key>PowerBook5,4</key>
<string>PowerBook G4 (15&quot; 1.5/1.33GHz)</string>
<key>PowerBook5,5</key>
<string>PowerBook G4 (17&quot; 1.5GHz)</string>
<key>PowerBook5,6</key>
<string>PowerBook G4 (15&quot; 1.67GHz/1.5GHz)</string>
<key>PowerBook5,7</key>
<string>PowerBook G4 (17&quot; 1.67GHz)</string>
<key>PowerBook5,8</key>
<string>PowerBook G4 (Double layer SD 15&quot;)</string>
<key>PowerBook5,9</key>
<string>PowerBook G4 (Double layer SD 17&quot;)</string>
<key>PowerBook6,1</key>
<string>PowerBook G4 (12&quot;)</string>
<key>PowerBook6,2</key>
<string>PowerBook G4 (12&quot; DVI)</string>
<key>PowerBook6,4</key>
<string>PowerBook G4 (12&quot; 1.33GHz)</string>
<key>PowerBook6,8</key>
<string>PowerBook G4 (12&quot; 1.5GHz)</string>
<key>MacBook1,1</key>
<string>MacBook (Core Duo)</string>
<key>MacBook2,1</key>
<string>MacBook (Core 2 Duo)</string>
<key>MacBook4,1</key>
<string>MacBook (2008)</string>
<key>MacBook5,1</key>
<string>MacBook (Unibody)</string>
<key>MacBook5,2</key>
<string>MacBook (White 2009)</string>
<key>MacBook6,1</key>
<string>MacBook (White Unibody)</string>
<key>MacBookAir1,1</key>
<string>MacBook Air (2008)</string>
<key>MacBookPro1,1</key>
<string>MacBook Pro Core Duo (15&quot;)</string>
<key>MacBookPro1,2</key>
<string>MacBook Pro Core Duo (17&quot;)</string>
<key>MacBookPro2,1</key>
<string>MacBook Pro Core 2 Duo (17&quot;)</string>
<key>MacBookPro2,2</key>
<string>MacBook Pro Core 2 Duo (15&quot;)</string>
<key>MacBookPro3,1</key>
<string>MacBook Pro Core 2 Duo (15&quot; LED Core 2 Duo)</string>
<key>MacBookPro3,2</key>
<string>MacBook Pro Core 2 Duo (17&quot; HD Core 2 Duo)</string>
<key>MacBookPro4,1</key>
<string>MacBook Pro (Core 2 Duo 2008)</string>
<key>MacBookPro5,1</key>
<string>MacBook Pro (Unibody)</string>
<key>MacBookPro5,2</key>
<string>MacBook Pro (Unibody 17&quot; 2009)</string>
<key>MacBookPro5,3</key>
<string>MacBook Pro (Unibody 15&quot; 2009)</string>
<key>MacBookPro5,4</key>
<string>MacBook Pro (Unibody 15&quot; 2009)</string>
<key>MacBookPro5,5</key>
<string>MacBook Pro (Unibody 13&quot; 2009)</string>
<key>PowerMac1,1</key>
<string>Power Macintosh G3 (Blue &amp; White)</string>
<key>PowerMac1,2</key>
<string>Power Macintosh G4 (PCI Graphics)</string>
<key>PowerMac11,2</key>
<string>Power Macintosh G5 (2005)</string>
<key>PowerMac3,1</key>
<string>Power Macintosh G4 (AGP Graphics)</string>
<key>PowerMac3,2</key>
<string>Power Macintosh G4 (AGP Graphics)</string>
<key>PowerMac3,3</key>
<string>Power Macintosh G4 (Gigabit Ethernet)</string>
<key>PowerMac3,4</key>
<string>Power Macintosh G4 (Digital Audio)</string>
<key>PowerMac3,5</key>
<string>Power Macintosh G4 (Quick Silver)</string>
<key>PowerMac3,6</key>
<string>Power Macintosh G4 (Mirrored Drive Door)</string>
<key>PowerMac5,1</key>
<string>Power Macintosh G4 Cube</string>
<key>PowerMac7,2</key>
<string>Power Macintosh G5</string>
<key>PowerMac7,3</key>
<string>Power Macintosh G5</string>
<key>PowerMac9,1</key>
<string>Power Macintosh G5 (2005)</string>
<key>MacPro1,1</key>
<string>Mac Pro (Four-Core)</string>
<key>MacPro2,1</key>
<string>Mac Pro (Eight-Core)</string>
<key>MacPro3,1</key>
<string>Mac Pro (2008 4/8 core &quot;Harpertown&quot;)</string>
<key>MacPro4,1</key>
<string>Mac Pro (2009 &quot;Nehalem&quot;)</string>
<key>RackMac1,1</key>
<string>Xserve G4</string>
<key>RackMac1,2</key>
<string>Xserve G4 (Slot-loading cluster node)</string>
<key>RackMac3,1</key>
<string>Xserve G5</string>
<key>Xserve1,1</key>
<string>Xserve (Intel Xeon)</string>
<key>Xserve2,1</key>
<string>Xserve (2008 Quad-Core)</string>
<key>Xserve3,1</key>
<string>Xserve (2009 Quad-Core)</string>
</dict>
</plist>

View File

@ -0,0 +1 @@
A

View File

@ -0,0 +1 @@
Versions/Current/Headers

View File

@ -0,0 +1 @@
Versions/Current/MGMUsers

Some files were not shown because too many files have changed in this diff Show More