mirror of
https://github.com/zakk4223/CocoaSplit.git
synced 2026-05-15 22:00:34 -06:00
314 lines
8.2 KiB
Objective-C
314 lines
8.2 KiB
Objective-C
//
|
|
// TwitchStreamService.m
|
|
// CSTwitchStreamServicePlugin
|
|
//
|
|
// Created by Zakk on 8/29/14.
|
|
// Copyright (c) 2014 Zakk. All rights reserved.
|
|
//
|
|
|
|
#import "TwitchStreamService.h"
|
|
#import "TwitchStreamServiceViewController.h"
|
|
|
|
|
|
@implementation TwitchStreamService
|
|
|
|
@synthesize accountName = _accountName;
|
|
|
|
-(instancetype) init
|
|
{
|
|
if(self = [super init])
|
|
{
|
|
self.isReady = YES;
|
|
self.knownAccounts = [[CSPluginServices sharedPluginServices] accountNamesForService:@"twitch"];
|
|
}
|
|
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
-(void)encodeWithCoder:(NSCoder *)aCoder
|
|
{
|
|
[aCoder encodeObject:self.selectedServer forKey:@"selectedServer"];
|
|
[aCoder encodeObject:self.streamKey forKey:@"streamKey"];
|
|
[aCoder encodeObject:self.accountName forKey:@"accountName"];
|
|
[aCoder encodeBool:self.alwaysFetchKey forKey:@"alwaysFetchKey"];
|
|
[aCoder encodeBool:self.bandwidthTest forKey:@"bandwidthTest"];
|
|
|
|
}
|
|
|
|
-(instancetype)initWithCoder:(NSCoder *)aDecoder
|
|
{
|
|
if (self = [self init])
|
|
{
|
|
self.selectedServer = [aDecoder decodeObjectForKey:@"selectedServer"];
|
|
self.streamKey = [aDecoder decodeObjectForKey:@"streamKey"];
|
|
self.accountName = [aDecoder decodeObjectForKey:@"accountName"];
|
|
self.alwaysFetchKey = [aDecoder decodeBoolForKey:@"alwaysFetchKey"];
|
|
self.bandwidthTest = [aDecoder decodeBoolForKey:@"bandwidthTest"];
|
|
|
|
}
|
|
return self;
|
|
}
|
|
|
|
|
|
-(NSViewController *)getConfigurationView
|
|
{
|
|
|
|
TwitchStreamServiceViewController *configViewController;
|
|
[self loadTwitchIngest];
|
|
|
|
configViewController = [[TwitchStreamServiceViewController alloc] initWithNibName:@"TwitchStreamServiceViewController" bundle:[NSBundle bundleForClass:self.class]];
|
|
configViewController.serviceObj = self;
|
|
return configViewController;
|
|
}
|
|
|
|
|
|
|
|
-(NSString *)getServiceFormat
|
|
{
|
|
return @"FLV";
|
|
}
|
|
|
|
|
|
-(NSString *)accountName
|
|
{
|
|
return _accountName;
|
|
}
|
|
|
|
-(void)setAccountName:(NSString *)accountName
|
|
{
|
|
_accountName = accountName;
|
|
self.oauthObject = nil;
|
|
}
|
|
|
|
|
|
-(void)prepareForStreamStart
|
|
{
|
|
if (self.alwaysFetchKey && !_key_fetch_pending)
|
|
{
|
|
@synchronized (self) {
|
|
self.streamKey = nil;
|
|
_key_fetch_pending = YES;
|
|
}
|
|
|
|
[self fetchTwitchStreamKey];
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-(NSString *)getServiceDestination
|
|
{
|
|
|
|
|
|
if (!self.streamKey)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
if (self.selectedServer)
|
|
{
|
|
NSString *destination;
|
|
|
|
NSString *baseDestination = [self.selectedServer stringByReplacingOccurrencesOfString:@"{stream_key}" withString:self.streamKey];
|
|
if (self.bandwidthTest)
|
|
{
|
|
destination = [NSString stringWithFormat:@"%@?bandwidthtest=true", baseDestination];
|
|
} else {
|
|
destination = baseDestination;
|
|
}
|
|
|
|
return destination;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
|
|
|
|
+(NSString *)label
|
|
{
|
|
return @"Twitch";
|
|
}
|
|
|
|
|
|
+(NSString *)serviceDescription
|
|
{
|
|
return @"Twitch";
|
|
}
|
|
|
|
|
|
+(NSImage *)serviceImage
|
|
{
|
|
NSImage *ret = [[NSBundle bundleForClass:[self class]] imageForResource:@"GlitchIcon_PurpleonWhite"];
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)createAuthenticator
|
|
{
|
|
if (!self.oauthObject)
|
|
{
|
|
|
|
if (!_oauth_client_id)
|
|
{
|
|
_oauth_client_id = [[NSBundle bundleForClass:[self class]] objectForInfoDictionaryKey:@"TwitchAPIClientID"];
|
|
}
|
|
|
|
NSDictionary *oconfig = @{kCSOauth2ConfigAuthURL:@"https://api.twitch.tv/kraken/oauth2/authorize", kCSOauth2ConfigRedirectURL:@"cocoasplit-twitch://cocoasplit.com/oauth/redirect", kCSOauth2ConfigScopes:@[@"channel_read", @"user_read"]};
|
|
|
|
self.oauthObject = [[CSPluginServices sharedPluginServices] createOAuth2Authenticator:@"twitch" clientID:_oauth_client_id flowType:kCSOauth2ImplicitGrantFlow config:oconfig];
|
|
|
|
|
|
self.oauthObject.accountName = self.accountName;
|
|
self.oauthObject.accountNameFetcher = ^void(CSOauth2Authenticator *authenticator) {
|
|
[self fetchAccountname:authenticator];
|
|
};
|
|
}
|
|
}
|
|
|
|
-(void)authenticateUser
|
|
{
|
|
self.accountName = nil;
|
|
|
|
[self createAuthenticator];
|
|
self.oauthObject.forceVerify = YES;
|
|
[self.oauthObject configurationVariableSet:@{@"force_verify": @"true"} forName:kCSOauth2ExtraAuthParams];
|
|
|
|
[self fetchTwitchStreamKey];
|
|
self.oauthObject.forceVerify = NO;
|
|
[self.oauthObject configurationVariableRemove:kCSOauth2ExtraAuthParams];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)fetchAccountname:(CSOauth2Authenticator *)authenticator
|
|
{
|
|
if (self.accountName)
|
|
{
|
|
[authenticator saveToKeychain:self.accountName];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
self.knownAccounts = [[CSPluginServices sharedPluginServices] accountNamesForService:@"twitch"];
|
|
});
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
if (self.oauthObject && self.oauthObject.accessToken)
|
|
{
|
|
NSString *apiString = @"https://api.twitch.tv/kraken/channel";
|
|
|
|
NSURL *apiURL = [NSURL URLWithString:apiString];
|
|
|
|
|
|
|
|
NSMutableURLRequest *apiRequest = [NSMutableURLRequest requestWithURL:apiURL];
|
|
|
|
[self.oauthObject jsonRequest:apiRequest completionHandler:^(id decodedData) {
|
|
|
|
NSDictionary *user_response = (NSDictionary *)decodedData;
|
|
NSString *account_name = [user_response objectForKey:@"name"];
|
|
[authenticator saveToKeychain:account_name];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
self.accountName = account_name;
|
|
self.knownAccounts = [[CSPluginServices sharedPluginServices] accountNamesForService:@"twitch"];
|
|
});
|
|
}];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-(void)fetchTwitchStreamKey
|
|
{
|
|
|
|
[self createAuthenticator];
|
|
|
|
NSString *apiString = @"https://api.twitch.tv/kraken/channel";
|
|
|
|
NSURL *apiURL = [NSURL URLWithString:apiString];
|
|
|
|
|
|
|
|
NSMutableURLRequest *apiRequest = [NSMutableURLRequest requestWithURL:apiURL];
|
|
|
|
|
|
//[apiRequest setValue:[NSString stringWithFormat:@"OAuth %@", self.oAuthKey] forHTTPHeaderField:@"Authorization"];
|
|
|
|
[self.oauthObject jsonRequest:apiRequest completionHandler:^(id decodedData) {
|
|
|
|
NSDictionary *channel_response = (NSDictionary *)decodedData;
|
|
NSString *stream_key = [channel_response objectForKey:@"stream_key"];
|
|
dispatch_async(dispatch_get_main_queue(), ^{self.streamKey = stream_key; _key_fetch_pending = NO;});
|
|
}];
|
|
}
|
|
|
|
|
|
-(void)loadTwitchIngest
|
|
{
|
|
|
|
NSString *apiString = @"https://api.twitch.tv/kraken/ingests";
|
|
|
|
NSURL *apiURL = [NSURL URLWithString:apiString];
|
|
|
|
NSMutableURLRequest *apiRequest = [NSMutableURLRequest requestWithURL:apiURL];
|
|
|
|
if (!_oauth_client_id)
|
|
{
|
|
_oauth_client_id = [[NSBundle bundleForClass:[self class]] objectForInfoDictionaryKey:@"TwitchAPIClientID"];
|
|
}
|
|
|
|
[apiRequest setValue:_oauth_client_id forHTTPHeaderField:@"Client-ID"];
|
|
[NSURLConnection sendAsynchronousRequest:apiRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *err) {
|
|
|
|
NSError *jsonError;
|
|
NSDictionary *ingest_response = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
|
|
//Handle error
|
|
|
|
NSArray *ingest_list = [ingest_response objectForKey:@"ingests"];
|
|
|
|
NSMutableArray *cooked_ingests = [[NSMutableArray alloc] init];
|
|
|
|
for (NSDictionary *tw_ingest in ingest_list)
|
|
{
|
|
|
|
NSMutableDictionary *ingest_map = [[NSMutableDictionary alloc] init];
|
|
|
|
NSString *url_temp = [tw_ingest objectForKey:@"url_template"];
|
|
NSString *name = [tw_ingest objectForKey:@"name"];
|
|
|
|
|
|
|
|
if (!url_temp || !name)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
[ingest_map setValue: url_temp forKey:@"destination"];
|
|
[ingest_map setValue:name forKey:@"name"];
|
|
[cooked_ingests addObject:ingest_map];
|
|
|
|
}
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{self.twitchServers = cooked_ingests; });
|
|
|
|
|
|
|
|
return;
|
|
}];
|
|
}
|
|
|
|
|
|
|
|
@end
|