Skip to content

Commit

Permalink
Support for age restricted videos
Browse files Browse the repository at this point in the history
  • Loading branch information
0xced committed Sep 10, 2014
1 parent fea6e3b commit 632eabb
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#### Version 2.0.3

* Support for age restricted videos.

#### Version 2.0.2

* Fixed errors on protected videos. (#52)
Expand Down

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions XCDYouTubeKit Tests/XCDYouTubeProtectedVideosTestCase.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,26 @@ - (void) testProtectedVEVOVideo
XCTAssertTrue([monitor waitWithTimeout:10]);
}

- (void) testAgeRestrictedVEVOVideo
{
TRVSMonitor *monitor = [TRVSMonitor monitor];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"07FYdnEawAQ" completionHandler:^(XCDYouTubeVideo *video, NSError *error)
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertNotNil(video.smallThumbnailURL);
XCTAssertNotNil(video.mediumThumbnailURL);
XCTAssertNotNil(video.largeThumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
XCTAssertTrue(video.duration > 0);
[video.streamURLs enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSURL *streamURL, BOOL *stop) {
XCTAssertTrue([streamURL.query rangeOfString:@"signature="].location != NSNotFound);
}];
[monitor signal];
}];
XCTAssertTrue([monitor waitWithTimeout:10]);
}

- (void) testProtectedVideoWithDollarSignature
{
TRVSMonitor *monitor = [TRVSMonitor monitor];
Expand Down
29 changes: 23 additions & 6 deletions XCDYouTubeKit/XCDYouTubeVideoOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ @interface XCDYouTubeVideoOperation () <NSURLConnectionDataDelegate, NSURLConnec
@property (atomic, assign) BOOL isFinished;

@property (atomic, strong) XCDYouTubeVideoWebpage *webpage;
@property (atomic, strong) XCDYouTubePlayerScript *playerScript;
@property (atomic, strong) XCDYouTubeVideo *noStreamVideo;
@property (atomic, strong) NSError *lastError;
@property (atomic, strong) NSError *youTubeError; // Error actually coming from the YouTube API, i.e. explicit and localized error
Expand Down Expand Up @@ -80,10 +81,10 @@ - (void) startRequestWithURL:(NSURL *)url
self.connection = connection;
}

- (void) handleVideoInfoResponseWithInfo:(NSDictionary *)info playerScript:(XCDYouTubePlayerScript *)playerScript
- (void) handleVideoInfoResponseWithInfo:(NSDictionary *)info
{
NSError *error = nil;
XCDYouTubeVideo *video = [[XCDYouTubeVideo alloc] initWithIdentifier:self.videoIdentifier info:info playerScript:playerScript response:self.response error:&error];
XCDYouTubeVideo *video = [[XCDYouTubeVideo alloc] initWithIdentifier:self.videoIdentifier info:info playerScript:self.playerScript response:self.response error:&error];
if (video)
{
[video mergeVideo:self.noStreamVideo];
Expand Down Expand Up @@ -124,12 +125,28 @@ - (void) handleWebPageResponse
- (void) handleJavaScriptPlayerResponse
{
NSString *script = [[NSString alloc] initWithData:self.connectionData encoding:NSISOLatin1StringEncoding];
XCDYouTubePlayerScript *playerScript = [[XCDYouTubePlayerScript alloc] initWithString:script];
self.playerScript = [[XCDYouTubePlayerScript alloc] initWithString:script];

if (playerScript)
[self handleVideoInfoResponseWithInfo:self.webpage.videoInfo playerScript:playerScript];
if (self.playerScript)
{
if (self.webpage.isAgeRestricted)
{
NSString *eurl = [@"https://youtube.googleapis.com/v/" stringByAppendingString:self.videoIdentifier];
NSString *sts = [self.webpage.playerConfiguration[@"sts"] description] ?: @"";
NSDictionary *query = @{ @"video_id": self.videoIdentifier, @"hl": self.languageIdentifier, @"eurl": eurl, @"sts": sts};
NSString *queryString = XCDQueryStringWithDictionary(query, NSUTF8StringEncoding);
NSURL *videoInfoURL = [NSURL URLWithString:[@"https://www.youtube.com/get_video_info?" stringByAppendingString:queryString]];
[self startRequestWithURL:videoInfoURL];
}
else
{
[self handleVideoInfoResponseWithInfo:self.webpage.videoInfo];
}
}
else
{
[self startNextVideoInfoRequest];
}
}

- (void) finishWithVideo:(XCDYouTubeVideo *)video
Expand Down Expand Up @@ -205,7 +222,7 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *videoQuery = [[NSString alloc] initWithData:self.connectionData encoding:NSASCIIStringEncoding];
NSDictionary *info = XCDDictionaryWithQueryString(videoQuery, NSUTF8StringEncoding);
[self handleVideoInfoResponseWithInfo:info playerScript:nil];
[self handleVideoInfoResponseWithInfo:info];
}
else if ([requestURL.path isEqualToString:@"/watch"])
{
Expand Down
2 changes: 2 additions & 0 deletions XCDYouTubeKit/XCDYouTubeVideoWebpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ __attribute__((visibility("hidden")))

- (instancetype) initWithData:(NSData *)data response:(NSURLResponse *)response;

@property (nonatomic, readonly) NSDictionary *playerConfiguration;
@property (nonatomic, readonly) NSDictionary *videoInfo;
@property (nonatomic, readonly) NSURL *javaScriptPlayerURL;
@property (nonatomic, readonly) BOOL isAgeRestricted;

@end
13 changes: 13 additions & 0 deletions XCDYouTubeKit/XCDYouTubeVideoWebpage.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ @implementation XCDYouTubeVideoWebpage
NSDictionary *_playerConfiguration;
NSDictionary *_videoInfo;
NSURL *_javaScriptPlayerURL;
BOOL _isAgeRestricted;
}

- (instancetype) initWithData:(NSData *)data response:(NSURLResponse *)response
Expand Down Expand Up @@ -88,4 +89,16 @@ - (NSURL *) javaScriptPlayerURL
return _javaScriptPlayerURL;
}

- (BOOL) isAgeRestricted
{
if (!_isAgeRestricted)
{
NSData *playerAgeGateContent = [@"player-age-gate-content" dataUsingEncoding:NSUTF8StringEncoding];
NSDataSearchOptions options = (NSDataSearchOptions)0;
NSRange range = NSMakeRange(0, self.data.length);
_isAgeRestricted = [self.data rangeOfData:playerAgeGateContent options:options range:range].location != NSNotFound;
}
return _isAgeRestricted;
}

@end

0 comments on commit 632eabb

Please sign in to comment.