HandBrake/macosx/HBRemoteCore.m

300 lines
8.4 KiB
Objective-C

/* This file is part of the HandBrake source code.
Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
#import "HBRemoteCore.h"
#import "HBRemoteCoreProtocol.h"
#import "HBPreferencesKeys.h"
@import HandBrakeKit;
@interface HBRemoteCore () <HBRemoteProgressProtocol>
@property (nonatomic, readonly) NSXPCConnection *connection;
@property (nonatomic, readonly) id<HBRemoteCoreProtocol> proxy;
@property (nonatomic, readwrite) HBState state;
@property (nonatomic, readonly) NSInteger level;
@property (nonatomic, readonly, copy) NSString *name;
@property (nonatomic, readonly, copy) NSString *serviceName;
@property (nonatomic, readwrite, copy) HBCoreProgressHandler progressHandler;
@property (nonatomic, readwrite, copy) HBCoreCompletionHandler completionHandler;
@end
@implementation HBRemoteCore
- (instancetype)init
{
self = [super init];
if (self)
{
_state = HBStateIdle;
_stdoutRedirect = HBRedirect.stdoutRedirect;
_stderrRedirect = HBRedirect.stderrRedirect;
_automaticallyPreventSleep = NO;
_level = 1;
_name = @"HandBrakeXPC";
_serviceName = @"fr.handbrake.HandBrakeXPCService";
}
return self;
}
- (instancetype)initWithLogLevel:(NSInteger)level name:(NSString *)name serviceName:(NSString *)serviceName
{
self = [self init];
if (self)
{
_level = level;
_name = [name copy];
_serviceName = [serviceName copy];
}
return self;
}
- (void)connect
{
_connection = [[NSXPCConnection alloc] initWithServiceName:self.serviceName];
_connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HBRemoteCoreProtocol)];
_connection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HBRemoteProgressProtocol)];
_connection.exportedObject = self;
__weak HBRemoteCore *weakSelf = self;
_connection.interruptionHandler = ^{
dispatch_sync(dispatch_get_main_queue(), ^{
[weakSelf handleInterruption];
});
};
_connection.invalidationHandler = ^{
dispatch_sync(dispatch_get_main_queue(), ^{
[weakSelf forwardError:@"XPC: Service connection was invalidated\n"];
});
};
_proxy = [_connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self forwardError:@"XPC: Service did report an error\n"];
[HBUtilities writeErrorToActivityLog:error];
});
}];
[_connection resume];
[_proxy initGlobal];
[_proxy setDVDNav:[NSUserDefaults.standardUserDefaults boolForKey:HBUseDvdNav]];
[_proxy setUpWithLogLevel:self.level name:self.name];
[_proxy setAutomaticallyPreventSleep:self.automaticallyPreventSleep];
}
- (void)invalidate
{
[[_connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {}] closeGlobal];
[_connection invalidate];
_connection = nil;
_proxy = nil;
}
- (void)handleInterruption
{
[_connection invalidate];
_connection = nil;
_proxy = nil;
if (self.state == HBStateIdle)
{
// XPC was idle and the system closed it
// to free ram, no need to restart it.
return;
}
else
{
HBCoreCompletionHandler handler = self.completionHandler;
self.progressHandler = nil;
self.completionHandler = nil;
self.state = HBStateIdle;
if (handler)
{
HBCoreResult result = {0, HBCoreResultCodeUnknown};
result.code = HBCoreResultCodeUnknown;
handler(result);
}
[self forwardError:@"XPC: Service did crash\n"];
}
}
- (void)updateState:(HBState)state
{
dispatch_sync(dispatch_get_main_queue(), ^{
self.state = state;
});
}
- (void)setLogLevel:(NSInteger)logLevel
{
_logLevel = logLevel;
[_proxy setLogLevel:logLevel];
}
- (void)setAutomaticallyPreventSleep:(BOOL)automaticallyPreventSleep
{
_automaticallyPreventSleep = automaticallyPreventSleep;
[_proxy setAutomaticallyPreventSleep:automaticallyPreventSleep];
}
- (void)allowSleep
{
[_proxy allowSleep];
}
- (void)preventSleep
{
[_proxy preventSleep];
}
- (void)scanURL:(NSURL *)url titleIndex:(NSUInteger)index previews:(NSUInteger)previewsNum minDuration:(NSUInteger)minSeconds maxDuration:(NSUInteger)maxSeconds keepPreviews:(BOOL)keepPreviews hardwareDecoder:(BOOL)hardwareDecoder keepDuplicateTitles:(BOOL)keepDuplicateTitles progressHandler:(nonnull HBCoreProgressHandler)progressHandler completionHandler:(nonnull HBCoreCompletionHandler)completionHandler
{
if (!_connection)
{
[self connect];
}
#ifdef __SANDBOX_ENABLED__
__block HBSecurityAccessToken *token = [HBSecurityAccessToken tokenWithObject:url];
NSData *bookmark = [url bookmarkDataWithOptions:0 includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
if (bookmark)
{
[_proxy provideResourceAccessWithBookmarks:@[bookmark]];
}
#endif
self.progressHandler = progressHandler;
self.completionHandler = completionHandler;
self.state = HBStateScanning;
__weak HBRemoteCore *weakSelf = self;
[_proxy scanURL:url titleIndex:index previews:previewsNum minDuration:minSeconds maxDuration:maxSeconds keepPreviews:keepPreviews hardwareDecoder:(BOOL)hardwareDecoder keepDuplicateTitles:(BOOL)keepDuplicateTitles withReply:^(HBCoreResult result) {
dispatch_sync(dispatch_get_main_queue(), ^{
HBCoreCompletionHandler handler = weakSelf.completionHandler;
weakSelf.completionHandler = nil;
weakSelf.progressHandler = nil;
#ifdef __SANDBOX_ENABLED__
token = nil;
#endif
handler(result);
});
}];
}
- (void)cancelScan
{
[_proxy cancelScan];
}
- (void)encodeJob:(HBJob *)job progressHandler:(HBCoreProgressHandler)progressHandler completionHandler:(HBCoreCompletionHandler)completionHandler
{
#ifdef __SANDBOX_ENABLED__
__block HBSecurityAccessToken *token = [HBSecurityAccessToken tokenWithObject:job];
NSMutableArray<NSData *> *bookmarks = [NSMutableArray array];
for (HBSubtitlesTrack *track in job.subtitles.tracks)
{
if (track.fileURL)
{
NSData *subtitlesBookmark = [track.fileURL bookmarkDataWithOptions:0 includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
if (subtitlesBookmark)
{
[bookmarks addObject:subtitlesBookmark];
}
}
}
NSData *destinationBookmark = [job.destinationFolderURL bookmarkDataWithOptions:0 includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
if (destinationBookmark)
{
[bookmarks addObject:destinationBookmark];
}
NSData *sourceBookmark = [job.fileURL bookmarkDataWithOptions:0 includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
if (sourceBookmark)
{
[bookmarks addObject:sourceBookmark];
}
[_proxy provideResourceAccessWithBookmarks:bookmarks];
#endif
self.progressHandler = progressHandler;
self.completionHandler = completionHandler;
self.state = HBStateWorking;
__weak HBRemoteCore *weakSelf = self;
[_proxy encodeJob:job withReply:^(HBCoreResult result) {
dispatch_sync(dispatch_get_main_queue(), ^{
HBCoreCompletionHandler handler = weakSelf.completionHandler;
weakSelf.completionHandler = nil;
weakSelf.progressHandler = nil;
#ifdef __SANDBOX_ENABLED__
token = nil;
#endif
handler(result);
});
}];
}
- (void)cancelEncode
{
[_proxy cancelEncode];
}
- (void)updateProgress:(double)currentProgress hours:(int)hours minutes:(int)minutes seconds:(int)seconds state:(HBState)state info:(NSString *)info
{
__weak HBRemoteCore *weakSelf = self;
dispatch_sync(dispatch_get_main_queue(), ^{
if (weakSelf.progressHandler)
{
HBProgress progress = {currentProgress , hours, minutes, seconds};
weakSelf.progressHandler(state, progress, info);
}
});
}
- (void)forwardOutput:(NSString *)text
{
[_stdoutRedirect forwardOutput:text];
[HBUtilities writeToActivityLogWithNoHeader:text];
}
- (void)forwardError:(NSString *)text
{
[_stdoutRedirect forwardOutput:text];
[HBUtilities writeToActivityLogWithNoHeader:text];
}
- (void)pause
{
[_proxy pauseEncode];
}
- (void)resume
{
[_proxy resumeEncode];
}
@end