Skip to content

Commit

Permalink
Merge branch 'release/2.8.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
SoneeJohn committed Nov 15, 2019
2 parents 7b4c57a + 6309af7 commit 21168d0
Show file tree
Hide file tree
Showing 31 changed files with 641 additions and 554 deletions.
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.1
module_version: 2.8.2

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.1/XCDYouTubeKit
github_file_prefix: https://github.com/0xced/XCDYouTubeKit/tree/2.8.2/XCDYouTubeKit
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>XCDYouTubeKit.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>XCDYouTubeKit</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#### Version 2.8.2

* Add new `streamURL` property on `XCDYouTubeVideo`
* Fixed Swift Package Manager (#441)
* Support iOS 13 in Demo Projects
* Support background playback (#427, #442)

#### Version 2.8.1

* Adaptation to YouTube API change. (#447, #448, #449)
Expand Down
14 changes: 10 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
// swift-tools-version:4.2
// swift-tools-version:5.1
import PackageDescription

let package = Package(
name: "XCDYouTubeKit",
// platforms: [.iOS("8.0"), .macOS("10.10"), tvOS("9.0")],
platforms: [
.iOS(.v8),
.tvOS(.v9),
.macOS(.v10_10)
],
products: [
.library(name: "XCDYouTubeKit", targets: ["XCDYouTubeKit"])
.library(name: "XCDYouTubeKit" , targets: ["XCDYouTubeKit"])
],
targets: [
.target(
name: "XCDYouTubeKit",
path: "XCDYouTubeKit"
path: ".",
sources: ["XCDYouTubeKit"],
publicHeadersPath: "XCDYouTubeKit"
)
]
)
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Platform](https://img.shields.io/cocoapods/p/XCDYouTubeKit.svg?style=flat)](http://cocoadocs.org/docsets/XCDYouTubeKit/)
[![Pod Version](https://img.shields.io/cocoapods/v/XCDYouTubeKit.svg?style=flat)](https://cocoapods.org/pods/XCDYouTubeKit)
[![Carthage Compatibility](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage/)
[![Accio supported](https://img.shields.io/badge/Accio-supported-0A7CF5.svg?style=flat)](https://github.com/JamitLabs/Accio)
[![Swift Package Manager Compatibility](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen)](ttps://swift.org/package-manager/)
[![License](https://img.shields.io/cocoapods/l/XCDYouTubeKit.svg?style=flat)](LICENSE)

**XCDYouTubeKit** is a YouTube video player for iOS, tvOS and macOS.
Expand All @@ -28,7 +28,7 @@ XCDYouTubeKit is against the YouTube [Terms of Service](https://www.youtube.com/

## Installation

XCDYouTubeKit is available through [CocoaPods](https://cocoapods.org/), [Carthage](https://github.com/Carthage/Carthage) and [Accio](https://github.com/JamitLabs/Accio).
XCDYouTubeKit is available through [CocoaPods](https://cocoapods.org/), [Carthage](https://github.com/Carthage/Carthage) and [Swift Package Manager](https://swift.org/package-manager/).

CocoaPods:

Expand All @@ -42,10 +42,14 @@ Carthage:
github "0xced/XCDYouTubeKit" ~> 2.8
```

Accio:
Swift Package Manager:

Add `XCDYouTubeKit` to the dependencies value of your `Package.swift`

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

Alternatively, you can manually use the provided static library or dynamic framework. In order to use the static library, you must:
Expand Down
47 changes: 27 additions & 20 deletions XCDYouTubeKit Demo/XCDYouTubeKit Demo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

214 changes: 214 additions & 0 deletions XCDYouTubeKit Demo/iOS Demo/AVPlayerViewControllerManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
//
// AVPlayerViewControllerManager.swift
// XCDYouTubeKit iOS Demo
//
// Created by Soneé John on 10/29/19.
// Copyright © 2019 Cédric Luthi. All rights reserved.
//

import Foundation
import AVKit
import MediaPlayer

extension UIViewController {
func topMostViewController() -> UIViewController {
if self.presentedViewController == nil {
return self
}
if let navigation = self.presentedViewController as? UINavigationController {
return navigation.visibleViewController!.topMostViewController()
}
if let tab = self.presentedViewController as? UITabBarController {
if let selectedTab = tab.selectedViewController {
return selectedTab.topMostViewController()
}
return tab.topMostViewController()
}
return self.presentedViewController!.topMostViewController()
}
}

extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if let viewController = parentResponder as? UIViewController {
return viewController
}
}
return nil
}
}

@objcMembers class AVPlayerViewControllerManager: NSObject {
//MARK: - Public
public static let shared = AVPlayerViewControllerManager()
public var lowQualityMode = false
public dynamic var duration: Float = 0

public var video: XCDYouTubeVideo? {
didSet {
guard let video = video else { return }
guard lowQualityMode == false else {
guard let streamURL = video.streamURLs[XCDYouTubeVideoQualityHTTPLiveStreaming] ?? video.streamURLs[XCDYouTubeVideoQuality.medium360.rawValue] ?? video.streamURLs[XCDYouTubeVideoQuality.small240.rawValue] else { fatalError("No stream URL") }

self.player = AVPlayer(url: streamURL)
self.controller.player = self.player
return
}
self.player = AVPlayer(url: video.streamURL)
self.controller.player = self.player
}
}

public var player: AVPlayer? {
didSet {
if let playerRateObserverToken = playerRateObserverToken {
playerRateObserverToken.invalidate()
self.playerRateObserverToken = nil
}

self.playerRateObserverToken = player?.observe(\.rate, changeHandler: { (item, value) in
self.updatePlaybackRateMetadata()
})

guard let video = self.video else { return }
if let token = timeObserverToken {
oldValue?.removeTimeObserver(token)
timeObserverToken = nil
}
self.setupRemoteTransportControls()
self.updateGeneralMetadata(video: video)
self.updatePlaybackDuration()
}
}

public lazy var controller: AVPlayerViewController = {
let controller = AVPlayerViewController()
if #available(iOS 10.0, *) {
controller.updatesNowPlayingInfoCenter = false
}
return controller
}()

override init() {
super.init()

NotificationCenter.default.addObserver(forName: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance(), queue: .main) { (notification) in

guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}

if type == .began {
self.player?.pause()
} else if type == .ended {
guard ((try? AVAudioSession.sharedInstance().setActive(true)) != nil) else { return }
guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
guard options.contains(.shouldResume) else { return }
self.player?.play()
}
}
}

public func disconnectPlayer() {
self.controller.player = nil
}

public func reconnectPlayer(rootViewController: UIViewController) {
let viewController = rootViewController.topMostViewController()
guard let playerViewController = viewController as? AVPlayerViewController else {
if rootViewController is UINavigationController {
guard let vc = (rootViewController as! UINavigationController).visibleViewController else { return }
for childVC in vc.children {
guard let playerViewController = childVC as? AVPlayerViewController else { continue }
playerViewController.player = self.player
break
}
}
return
}
playerViewController.player = self.player
}

//MARK: Private

fileprivate var playerRateObserverToken: NSKeyValueObservation?
fileprivate var timeObserverToken: Any?
fileprivate let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()

fileprivate func setupRemoteTransportControls() {
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.addTarget { [unowned self] event in
if self.player?.rate == 0.0 {
self.player?.play()
return .success
}
return .commandFailed
}

commandCenter.pauseCommand.addTarget { event in
if self.player?.rate == 1.0 {
self.player?.pause()
return .success
}
return .commandFailed
}
}

fileprivate func updateGeneralMetadata(video: XCDYouTubeVideo) {
guard player?.currentItem != nil else {
nowPlayingInfoCenter.nowPlayingInfo = nil
return
}

var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()
let title = video.title

if let thumbnailURL = video.thumbnailURL {
URLSession.shared.dataTask(with: thumbnailURL) { (data, _, error) in
guard error == nil else { return }
guard data != nil else { return }
guard let image = UIImage(data: data!) else { return }

let artwork = MPMediaItemArtwork(image: image)
nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
self.nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
}.resume()
}

nowPlayingInfo[MPMediaItemPropertyTitle] = title
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
}

fileprivate func updatePlaybackDuration() {
let interval = CMTime(seconds: 1.0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))

timeObserverToken = self.player?.addPeriodicTimeObserver(forInterval: interval, queue: .main, using: { [weak self] (time) in
guard let player = self?.player else { return }
guard player.currentItem != nil else { return }

var nowPlayingInfo = self!.nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()
self!.duration = Float(CMTimeGetSeconds(player.currentItem!.duration))
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = self!.duration
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = CMTimeGetSeconds(player.currentItem!.currentTime())
self!.nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
})
}

fileprivate func updatePlaybackRateMetadata() {
guard player?.currentItem != nil else {
duration = 0
nowPlayingInfoCenter.nowPlayingInfo = nil
return
}

var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player!.rate
nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = player!.rate
}
}
13 changes: 10 additions & 3 deletions XCDYouTubeKit Demo/iOS Demo/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import <XCDYouTubeKit/XCDYouTubeKit.h>

#import "ContextLogFormatter.h"
#import "XCDYouTubeKit_iOS_Demo-Swift.h"

@implementation AppDelegate

Expand All @@ -19,9 +20,6 @@ - (instancetype) init
if (!(self = [super init]))
return nil;

_playerEventLogger = [PlayerEventLogger new];
_nowPlayingInfoCenterProvider = [NowPlayingInfoCenterProvider new];

return self;
}

Expand Down Expand Up @@ -80,4 +78,13 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:
return YES;
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
[[AVPlayerViewControllerManager shared]disconnectPlayer];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
[[AVPlayerViewControllerManager shared]reconnectPlayerWithRootViewController:self.window.rootViewController];
}

@end
Loading

0 comments on commit 21168d0

Please sign in to comment.