Skip to content
This repository has been archived by the owner on Mar 29, 2022. It is now read-only.

Commit

Permalink
Changed network code to work with ios 9 and tv os
Browse files Browse the repository at this point in the history
  • Loading branch information
hellozimi committed Nov 4, 2015
1 parent 90fc9d5 commit c93b345
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 67 deletions.
1 change: 1 addition & 0 deletions YoutubeParser/Classes/HCYoutubeParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@


#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

typedef enum {
YouTubeThumbnailDefault,
Expand Down
141 changes: 74 additions & 67 deletions YoutubeParser/Classes/HCYoutubeParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ @implementation NSString (QueryString)

- (NSString *)stringByDecodingURLFormat {
NSString *result = [self stringByReplacingOccurrencesOfString:@"+" withString:@" "];
result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
result = [result stringByRemovingPercentEncoding];
return result;
}

Expand Down Expand Up @@ -109,77 +109,85 @@ + (NSDictionary *)h264videosWithYoutubeID:(NSString *)youtubeID {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:kUserAgent forHTTPHeaderField:@"User-Agent"];
[request setHTTPMethod:@"GET"];

NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

if (!error) {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

NSMutableDictionary *parts = [responseString dictionaryFromQueryStringComponents];

if (parts) {
NSString *fmtStreamMapString = [[parts objectForKey:@"url_encoded_fmt_stream_map"] objectAtIndex:0];
if (fmtStreamMapString.length > 0) {

NSArray *fmtStreamMapArray = [fmtStreamMapString componentsSeparatedByString:@","];
NSMutableDictionary *videoDictionary = [NSMutableDictionary dictionary];

for (NSString *videoEncodedString in fmtStreamMapArray) {
NSMutableDictionary *videoComponents = [videoEncodedString dictionaryFromQueryStringComponents];
NSString *type = [[[videoComponents objectForKey:@"type"] objectAtIndex:0] stringByDecodingURLFormat];
NSString *signature = nil;

if (![videoComponents objectForKey:@"stereo3d"]) {
if ([videoComponents objectForKey:@"itag"]) {
signature = [[videoComponents objectForKey:@"itag"] objectAtIndex:0];
}

if (signature && [type rangeOfString:@"mp4"].length > 0) {
NSString *url = [[[videoComponents objectForKey:@"url"] objectAtIndex:0] stringByDecodingURLFormat];
url = [NSString stringWithFormat:@"%@&signature=%@", url, signature];

NSString *quality = [[[videoComponents objectForKey:@"quality"] objectAtIndex:0] stringByDecodingURLFormat];
if ([videoComponents objectForKey:@"stereo3d"] && [[videoComponents objectForKey:@"stereo3d"] boolValue]) {
quality = [quality stringByAppendingString:@"-stereo3d"];

__block NSDictionary *data = nil;

// Lock threads with semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable responseData, NSURLResponse * _Nullable response, NSError * _Nullable error) {

if (!error) {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

NSMutableDictionary *parts = [responseString dictionaryFromQueryStringComponents];

if (parts) {
NSString *fmtStreamMapString = [[parts objectForKey:@"url_encoded_fmt_stream_map"] objectAtIndex:0];
if (fmtStreamMapString.length > 0) {

NSArray *fmtStreamMapArray = [fmtStreamMapString componentsSeparatedByString:@","];
NSMutableDictionary *videoDictionary = [NSMutableDictionary dictionary];

for (NSString *videoEncodedString in fmtStreamMapArray) {
NSMutableDictionary *videoComponents = [videoEncodedString dictionaryFromQueryStringComponents];
NSString *type = [[[videoComponents objectForKey:@"type"] objectAtIndex:0] stringByDecodingURLFormat];
NSString *signature = nil;

if (![videoComponents objectForKey:@"stereo3d"]) {
if ([videoComponents objectForKey:@"itag"]) {
signature = [[videoComponents objectForKey:@"itag"] objectAtIndex:0];
}
if([videoDictionary valueForKey:quality] == nil) {
[videoDictionary setObject:url forKey:quality];

if (signature && [type rangeOfString:@"mp4"].length > 0) {
NSString *url = [[[videoComponents objectForKey:@"url"] objectAtIndex:0] stringByDecodingURLFormat];
url = [NSString stringWithFormat:@"%@&signature=%@", url, signature];

NSString *quality = [[[videoComponents objectForKey:@"quality"] objectAtIndex:0] stringByDecodingURLFormat];
if ([videoComponents objectForKey:@"stereo3d"] && [[videoComponents objectForKey:@"stereo3d"] boolValue]) {
quality = [quality stringByAppendingString:@"-stereo3d"];
}
if([videoDictionary valueForKey:quality] == nil) {
[videoDictionary setObject:url forKey:quality];
}
}
}
}
}

// add some extra information about this video to the dictionary we pass back to save on the amounts of network requests
if (videoDictionary.count > 0)
{
NSMutableDictionary *optionsDict = [NSMutableDictionary dictionary];
NSArray *keys = @[//@"author", // youtube channel name
//@"avg_rating", // average ratings on yt when downloaded
@"iurl", //@"iurlmaxres", @"iurlsd", // thumbnail urls
//@"keywords", // author defined keywords
@"length_seconds", // total duration in seconds
@"title", // video title
//@"video_id"
]; // youtube id

for (NSString *key in keys)
// add some extra information about this video to the dictionary we pass back to save on the amounts of network requests
if (videoDictionary.count > 0)
{
[optionsDict setObject:parts[key][0] forKey:key]; // [0] because we want the object and not the array
NSMutableDictionary *optionsDict = [NSMutableDictionary dictionary];
NSArray *keys = @[//@"author", // youtube channel name
//@"avg_rating", // average ratings on yt when downloaded
@"iurl", //@"iurlmaxres", @"iurlsd", // thumbnail urls
//@"keywords", // author defined keywords
@"length_seconds", // total duration in seconds
@"title", // video title
//@"video_id"
]; // youtube id

for (NSString *key in keys)
{
[optionsDict setObject:parts[key][0] forKey:key]; // [0] because we want the object and not the array
}

[videoDictionary setObject:optionsDict forKey:@"moreInfo"];
}

[videoDictionary setObject:optionsDict forKey:@"moreInfo"];
data = videoDictionary;
dispatch_semaphore_signal(semaphore);
}
// Check for live data
else if ([parts objectForKey:@"live_playback"] != nil && [parts objectForKey:@"hlsvp"] != nil && [[parts objectForKey:@"hlsvp"] count] > 0) {
data = @{ @"live": [parts objectForKey:@"hlsvp"][0] };
dispatch_semaphore_signal(semaphore);
}

return videoDictionary;
}
// Check for live data
else if ([parts objectForKey:@"live_playback"] != nil && [parts objectForKey:@"hlsvp"] != nil && [[parts objectForKey:@"hlsvp"] count] > 0) {
return @{ @"live": [parts objectForKey:@"hlsvp"][0] };
}
}
}
}] resume];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

return data;
}
return nil;
}
Expand Down Expand Up @@ -270,16 +278,16 @@ + (void)thumbnailForYoutubeID:(NSString *)youtubeID thumbnailSize:(YouTubeThumbn
[request setValue:kUserAgent forHTTPHeaderField:@"User-Agent"];
[request setHTTPMethod:@"GET"];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
completeBlock(image, nil);
}
else {
completeBlock(nil, error);
}
}];
}] resume];
}
else {
NSDictionary *details = @{ NSLocalizedDescriptionKey : @"Could not find a valid Youtube ID" };
Expand All @@ -295,8 +303,7 @@ + (void)detailsForYouTubeURL:(NSURL *)youtubeURL
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:kYoutubeDataURL, youtubeID]]];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
Expand All @@ -311,7 +318,7 @@ + (void)detailsForYouTubeURL:(NSURL *)youtubeURL
else {
completeBlock(nil, error);
}
}];
}] resume];
}
else
{
Expand Down

0 comments on commit c93b345

Please sign in to comment.