Skip to content

Commit

Permalink
Merge branch 'release/2.9.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
SoneeJohn committed Feb 6, 2020
2 parents 33e9463 + f075a60 commit f94baed
Show file tree
Hide file tree
Showing 27 changed files with 841 additions and 130 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ XcodeCoverage
RELEASE_NOTES.md
.DS_Store
*.xcuserstate
xcuserdata/
/release.sh
4 changes: 2 additions & 2 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ source_directory: XCDYouTubeKit
framework_root: .
umbrella_header: XCDYouTubeKit/XCDYouTubeKit.h
module: XCDYouTubeKit
module_version: 2.8.3
module_version: 2.9.0

author: Cédric Luthi
author_url: https://twitter.com/0xced

readme: README.md
github_url: https://github.com/0xced/XCDYouTubeKit
github_file_prefix: https://github.com/0xced/XCDYouTubeKit/tree/2.8.3/XCDYouTubeKit
github_file_prefix: https://github.com/0xced/XCDYouTubeKit/tree/2.9.0/XCDYouTubeKit
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#### Version 2.9.0

* Add the ability to use custom regular expression patterns via `-[XCDYouTubeClient getVideoWithIdentifier:cookies:customPatterns:completionHandler:]` & `initWithVideoIdentifier:cookies:languageIdentifier:customPatterns` (#463, #199)
* Add new `viewCount` property in `XCDYouTubeVideo` (#460)
* Silence warning about deprecated implementation (#450)

#### Version 2.8.3

* Adaptation to YouTube API change. (#458)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ XCDYouTubeKit is available through [CocoaPods](https://cocoapods.org/), [Carthag
CocoaPods:

```ruby
pod "XCDYouTubeKit", "~> 2.8"
pod "XCDYouTubeKit", "~> 2.9"
```

Carthage:

```objc
github "0xced/XCDYouTubeKit" ~> 2.8
github "0xced/XCDYouTubeKit" ~> 2.9
```

Swift Package Manager:
Expand All @@ -48,7 +48,7 @@ Add `XCDYouTubeKit` to the dependencies value of your `Package.swift`

```swift
dependencies: [
.package(url: "https://github.com/0xced/XCDYouTubeKit.git", from: "2.8.0")
.package(url: "https://github.com/0xced/XCDYouTubeKit.git", from: "2.9.0")
]
```

Expand Down
33 changes: 33 additions & 0 deletions REGULAR_EXPRESSION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Regular Expression Guide

### Overview

Some YouTube videos require regular expressions for the XCDYouTubeKit to successfully parse them get a valid streaming URL. XCDYouTubeKit handles this automatically with hard-coded regular expression patterns, however, due to the changing nature of YouTube sometimes these patterns become out of date. Since version 2.9.0 clients have been given the ability to use custom patterns in favor of the hard-coded patterns used internally by the library. Before using custom patterns please note:

* The regular expressions are based on those used by the [YouTube extractor module](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/youtube.py) of the *youtube-dl* project. See the list of expressions [here](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L1344)
* The order of the expressions are very important, adding the expressions to an array in an incorrect order can lead to some videos being unable to play.
* The strings contained in the array passed to the `customPatterns` argument should be [ICU regular expressions](http://userguide.icu-project.org/strings/regexp).

### Best Practices

Generally speaking, the only time you would use the custom patterns is so that you can push new changes to your users faster and remotely, this would be done by using a server. Here are some best practices when using custom patterns :

* Make sure that you're using the latest version of `XCDYouTubeKit`.
* Check the current patterns being used by the library under the section titled "Current Patterns"
* Update the patterns accordingly on your server, this will allow users who haven't updated to the latest version of your app to use the latest patterns.

### Current Patterns

These are the patterns used in version 2.9.0 of XCDYouTubeKit:

```
\\b[cs]\\s*&&\\s*[adf]\\.set\\([^,]+\\s*,\\s*encodeURIComponent\\s*\\(\\s*([a-zA-Z0-9$]+)\\(
\\b[a-zA-Z0-9]+\\s*&&\\s*[a-zA-Z0-9]+\\.set\\([^,]+\\s*,\\s*encodeURIComponent\\s*\\(\\s*([a-zA-Z0-9$]+)\\(
\\b([a-zA-Z0-9$]{2})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)
([a-zA-Z0-9$]+)\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)
```

**Note**: Sometimes videos may still fail due to stream even if the patterns are up to date and would require an updated version of XCDYouTubeKit. Updated patterns won't always fix issues when YouTube changes its API, however, when the change merely requires new patterns using custom patterns should be sufficient.
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2.8.3;
CURRENT_PROJECT_VERSION = 2.9.0;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
Expand Down Expand Up @@ -804,7 +804,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 2.8.3;
CURRENT_PROJECT_VERSION = 2.9.0;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
Expand Down

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions XCDYouTubeKit Tests/XCDYouTubeClientTestCase.m
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ - (void) testMobileRestrictedVideo
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -122,6 +123,7 @@ - (void) testLiveVideo
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertNotNil(video.streamURLs[XCDYouTubeVideoQualityHTTPLiveStreaming]);
[expectation fulfill];
Expand All @@ -138,6 +140,7 @@ - (void) testVideo1
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
XCTAssertTrue(video.duration > 0);
Expand All @@ -158,6 +161,7 @@ - (void) testVideo1IsPlayable
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand Down
128 changes: 128 additions & 0 deletions XCDYouTubeKit Tests/XCDYouTubeProtectedVideosTestCase.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ - (void) testAgeRestrictedVideoThatRequiresCookiesWithUserCookies
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -71,6 +72,7 @@ - (void) testAgeRestrictedVideoThatRequiresCookiesWithUserCookiesIsPlayable
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand Down Expand Up @@ -109,6 +111,7 @@ - (void) testAgeRestrictedVideo
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -129,6 +132,7 @@ - (void) testAgeRestrictedUnratedVideo
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -142,13 +146,131 @@ - (void) testAgeRestrictedUnratedVideo
[self waitForExpectationsWithTimeout:5 handler:nil];
}

- (void) testProtectedVEVOVideoWithInvalidCustomPattern
{
//Although, this uses a valid regular expression (xxxxxxx) it does not match the signature function in `XCDYouTubePlayerScript`
__weak XCTestExpectation *expectation = [self expectationWithDescription:@""];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"rId6PKlDXeU" cookies:nil customPatterns:@[@"xxxxxxx"] completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error)
{
XCTAssertNotNil(error);
XCTAssertNil(video);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:nil];
}

- (void) testProtectedVEVOVideoWithNilCustomPatternIsPlayable
{
//If a nil array is passed then we should fallback to the hard-coded patterns

__weak XCTestExpectation *expectation = [self expectationWithDescription:@""];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"rId6PKlDXeU" cookies:nil customPatterns:nil completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error)
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
XCTAssertTrue(video.duration > 0);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:video.streamURLs[@(XCDYouTubeVideoQualityMedium360)]];
request.HTTPMethod = @"HEAD";
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError)
{
XCTAssertEqual([(NSHTTPURLResponse *)response statusCode], 200);
[expectation fulfill];
}];
[dataTask resume];
}];
[self waitForExpectationsWithTimeout:100 handler:nil];
}

- (void) testProtectedVEVOVideoWithEmptyCustomPatternIsPlayable
{
//If an empty array is passed then we should fallback to the hard-coded patterns

__weak XCTestExpectation *expectation = [self expectationWithDescription:@""];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"rId6PKlDXeU" cookies:nil customPatterns:@[] completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error)
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
XCTAssertTrue(video.duration > 0);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:video.streamURLs[@(XCDYouTubeVideoQualityMedium360)]];
request.HTTPMethod = @"HEAD";
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError)
{
XCTAssertEqual([(NSHTTPURLResponse *)response statusCode], 200);
[expectation fulfill];
}];
[dataTask resume];
}];
[self waitForExpectationsWithTimeout:100 handler:nil];
}

- (void) testProtectedVEVOVideoWithInvalidCustomPatternIsPlayable
{
//Although, this uses an invalid regular expression `{{{{{` the video should still be playable because we fallback to the hard-coded patterns in `XCDYouTubePlayerScript`.

__weak XCTestExpectation *expectation = [self expectationWithDescription:@""];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"rId6PKlDXeU" cookies:nil customPatterns:@[@"{{{{{"] completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error)
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
XCTAssertTrue(video.duration > 0);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:video.streamURLs[@(XCDYouTubeVideoQualityMedium360)]];
request.HTTPMethod = @"HEAD";
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError)
{
XCTAssertEqual([(NSHTTPURLResponse *)response statusCode], 200);
[expectation fulfill];
}];
[dataTask resume];
}];
[self waitForExpectationsWithTimeout:5 handler:nil];
}

- (void) testProtectedVEVOVideoWithValidCustomPatternIsPlayable
{
//Here we're testing if pattern `\\b([a-zA-Z0-9$]{2})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)` works, this pattern is valid as of Feb 5, 2020 and works for video id `rId6PKlDXeU`

__weak XCTestExpectation *expectation = [self expectationWithDescription:@""];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"rId6PKlDXeU" cookies:nil customPatterns:@[@"\\b([a-zA-Z0-9$]{2})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)"] completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error)
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
XCTAssertTrue(video.duration > 0);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:video.streamURLs[@(XCDYouTubeVideoQualityMedium360)]];
request.HTTPMethod = @"HEAD";
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError)
{
XCTAssertEqual([(NSHTTPURLResponse *)response statusCode], 200);
[expectation fulfill];
}];
[dataTask resume];
}];
[self waitForExpectationsWithTimeout:100 handler:nil];
}

- (void) testProtectedVEVOVideo1
{
__weak XCTestExpectation *expectation = [self expectationWithDescription:@""];
[[XCDYouTubeClient defaultClient] getVideoWithIdentifier:@"rId6PKlDXeU" completionHandler:^(XCDYouTubeVideo *video, NSError *error)
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -169,6 +291,7 @@ - (void) testProtectedVEVOVideo2
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -189,6 +312,7 @@ - (void) testProtectedVEVOVideo3
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -209,6 +333,7 @@ - (void) testProtectedVEVOIsPlayable
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand Down Expand Up @@ -251,6 +376,7 @@ - (void) testAgeRestrictedVEVOVideoWithUserCookies
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand All @@ -272,6 +398,7 @@ - (void) testAgeRestrictedVEVOVideoWithUserCookiesIsPlayable
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand Down Expand Up @@ -410,6 +537,7 @@ - (void) testAgeRestrictedVideo1
{
XCTAssertNil(error);
XCTAssertNotNil(video.title);
XCTAssertTrue(video.viewCount > 0);
XCTAssertNotNil(video.expirationDate);
XCTAssertNotNil(video.thumbnailURL);
XCTAssertTrue(video.streamURLs.count > 0);
Expand Down
2 changes: 1 addition & 1 deletion XCDYouTubeKit.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "XCDYouTubeKit"
s.version = "2.8.3"
s.version = "2.9.0"
s.summary = "YouTube video player for iOS and OS X."
s.homepage = "https://github.com/0xced/XCDYouTubeKit"
s.screenshot = "https://raw.github.com/0xced/XCDYouTubeKit/#{s.version}/Screenshots/XCDYouTubeVideoPlayerViewController.png"
Expand Down
Loading

0 comments on commit f94baed

Please sign in to comment.