SwiftでFacebook Graph APIを叩いてFacebookページの動画一覧を取得→動画再生

# 概要

動画メディアの時代なのでfacebookページから動画を取得したいときがあると思います。

今回は、

[Page Videos](https://developers.facebook.com/docs/graph-api/reference/page/videos/)のAPIで動画一覧を取得してidをモデルに保存、そのidを使って[Video](
https://stackoverflow.com/questions/39451169/swift-play-a-facebook-video-using-an-avplayer)のAPIを叩いて動画詳細ページで動画を再生する方法を紹介します。

Facebook GraphAPIの基本的な使い方については [本家のドキュメント](https://developers.facebook.com/docs/graph-api)で勉強してください :thumbsup: アクセストークンががないとリクエストできないです。あとSDKとかcocoapodsで入れてください。

[グラフAPIエクスプローラ](https://developers.facebook.com/tools/explorer/)でいろいろレスポンスをテストできるので試しながら実装してみましょう。

# コードサンプル

以下は https://www.facebook.com/commonfitness/ というフィットネス動画メディアから動画一覧を取得したい時のコードのサンプルです。

Videoのモデルを作ってそのモデルをcollectionViewのセルに渡してサムネを表示することを想定しています。

## 動画一覧の取得

```swift
class Video {
    
    var id = ""
    var imageUrl = ""
    var title = ""
}

class HomeViewController: UIViewController {

@IBOutlet weak var collectionView: UICollectionView!

var videos: [Video] = []

override func viewDidLoad() {
        super.viewDidLoad()
        self.getVideos()
}

func getVideos(){
        // facebook
        let graphRequest:FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "/commonfitness/videos", parameters: nil, httpMethod: "GET")
        graphRequest.start(completionHandler: { (connection, result, error) -> Void in
            
            if error != nil {
                print(error.debugDescription)
            } else {
                guard let videos = result as? [String: Any] else { return }
                guard let datas = videos["data"] as? [[String: String]] else { return }
                
                for data in datas {
                    let video = Video()
                    
                    if let title = data["description"] {
                        video.title = title
                    }
                    
                    if let id = data["id"] {
                        video.id = id
                    }
                    self.videos.append(video)
                }
                self.collectionView.reloadData()
            }
        })
    }

}

extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout  {

...

}
```

https://developers.facebook.com/docs/graph-api/reference/page/videos/

## idから小サムネイルの取得(楽だけど小さすぎ)

```swift
// こっちの方が多少取得が早いけれど画像が荒い
    private func setThumbnailVeryEasy(_ videoId: String){
        let imgUrl = "https://graph.facebook.com/\(videoId)/picture?fields=full_picture"
        let url = URL(string: imgUrl)
        imageView.sd_setImage(with: url)
    }
```

https://stackoverflow.com/questions/32155110/how-to-get-facebook-video-thumbnail-from-a-given-video-id-using-php

## idから大サムネイルの取得(またAPIたたかなければいけない)

```swift
// こっちは認証しないと取得できないけどサムネイルがめちゃ綺麗
    private func setClearThumbNail(_ videoId: String){
        let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "/\(videoId)/thumbnails", parameters: nil, httpMethod: "GET")
        graphRequest.start(completionHandler: { (connection, result, error) -> Void in
            
            if error != nil {
                print(error.debugDescription)
            } else {
                guard let datas = result as? [String: Any] else { return }
                guard let data = datas["data"] as? [[String: Any]] else { return }
                guard let firstData: [String: Any] = data.first else { return }
                guard let imgUrl = firstData["uri"] as? String else { return }
                let url = URL(string: imgUrl)
                self.imageView.sd_setImage(with: url)
            }
        })
    }
```

https://developers.facebook.com/docs/graph-api/reference/video/thumbnails/

## 動画詳細ページ

idから動画のdata受け取ってAVPlayerで再生するまで。

動画のURLを取得した後は、
 [SwiftでVideo Player](http://qiita.com/naoto0822/items/07da0e96aab0e3e2a64f) のやり方で動画を再生します。

```swift

class VideoViewController: UIViewController {

    @IBOutlet weak var movieView: AVPlayerView!

    var video = Video()
    var videoPlayer : AVPlayer!
    private var playerObserver: Any?

override func viewDidLoad() {
        super.viewDidLoad()
        
        title = video.title
        requestFacebookVideoData()
    }
    
    deinit {
        guard let observer = playerObserver else { return }
        NotificationCenter.default.removeObserver(observer)
    }
    
    private func requestFacebookVideoData(){
        // facebook
        let params = ["fields": "source"]
        let videoId = video.id
        let graphRequest:FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "/\(videoId)", parameters: params, httpMethod: "GET")
        graphRequest.start(completionHandler: { (connection, result, error) -> Void in
            
            if error != nil {
                print(error.debugDescription)
            } else {
                guard let data = result as? [String: String] else { return }
                
                if let source = data["source"]  {
                    self.setupVideoPlayer(source)
                }
            }
        })
    }
    
    private func setupVideoPlayer(_ urlString: String){
        let url = URL(string: urlString)
        let avAsset = AVURLAsset(url: url!)
        let playerItem = AVPlayerItem(asset: avAsset)
        videoPlayer = AVPlayer(playerItem: playerItem)
        
        // リピート再生したかったので書いたやつ
        let resetPlayer = {
            self.videoPlayer.seek(to: kCMTimeZero)
            self.videoPlayer.play()
        }
        playerObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: videoPlayer.currentItem, queue: nil) { notification in
            resetPlayer()
        }
        
        movieView.setVideoGravity(.resizeAspect)
        movieView.setPlayer(videoPlayer)
        self.videoPlayer.play()
    }

}

```

https://stackoverflow.com/questions/39451169/swift-play-a-facebook-video-using-an-avplayer

以上。

# 注意点

* アクセストークンがないとGraph APIでリクエストできないので、Facebookログインさせてユーザーのアクセストークンを取得するか、ページアクセストークンやアプリアクセストークンをサーバーから取得してリクエストする必要があります。

* ページアクセストークンやアプリアクセストークンはアプリ内にハードコーディングするとセキュリティ的にマズイとのこと

https://developers.facebook.com/docs/facebook-login/access-tokens/

# 参考リンク

https://developers.facebook.com/docs/graph-api/reference/page/videos/

https://developers.facebook.com/docs/graph-api/reference/v2.9/video

https://developers.facebook.com/docs/graph-api/reference/video/thumbnails/

https://stackoverflow.com/questions/39451169/swift-play-a-facebook-video-using-an-avplayer

https://stackoverflow.com/questions/32155110/how-to-get-facebook-video-thumbnail-from-a-given-video-id-using-php

http://qiita.com/naoto0822/items/07da0e96aab0e3e2a64f