         
         playerView.frame = view.bounds
     }
-    
-    func loadVideo() {
-        client.rac_getVideoWithIdentifier(videoInfo.id)
-            .startWithResult { [weak self] (result: Result<XCDYouTubeVideo, NSError>) in
-                guard let this = self else { return }
-                guard let streamUrl = result.value?.streamURLs[XCDYouTubeVideoQualityHTTPLiveStreaming] else { return }
-                let player = AVPlayer(url: streamUrl)
-                this.playerView.player = player
-                if this.playWhenReady == true {
-                    player.play()
-                }
-            }
-    }
-    
-    func playVideo() {
-        guard let player = self.playerView.player else {
-            self.playWhenReady = true
-            return
-        }
-        player.play()
-    }
-    
-    func stopVideo() {
-        self.playerView.player?.pause()
-    }
-    
-    func togglePlayPause() {
-        guard let player = self.playerView.player else { return }
-        let playState = player.rate == 1
-        playState ? player.pause() : player.play()
+}
+
+final class InfoViewController: UIViewController {
+    enum ViewData {
+        case normal(String)
+        case error(String)
+    }
+    
+    let infoLabel: UILabel = {
+        let label = UILabel()
+        label.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.title1) // UIFont.systemFont(ofSize: 24, weight: UIFontWeightSemibold)
+        label.numberOfLines = 0
+        label.textAlignment = .center
+        return label
+    }()
+    
+    let viewData: ViewData
+    
+    init(_ viewData: ViewData) {
+        self.viewData = viewData
+        
+        super.init(nibName: nil, bundle: nil)
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
+                
+        view |+| [ blurView]
+        blurView.contentView |+| [ infoLabel ]
+        
+        blurView |=| view
+        infoLabel |=| blurView.m_edges ~ (80, 80, 80, 80)
+        
+        switch viewData {
+        case .normal(let text):
+            infoLabel.text = text
+            infoLabel.textColor = UIColor.black
+        case .error(let text):
+            infoLabel.text = text
+            infoLabel.textColor = UIColor.red
+        }
     }
 }
 

        self.view.sendSubview(toBack: backgroundView)
        
        let playButtonTapGesture = UITapGestureRecognizer()
        playButtonTapGesture.addTarget(self, action: #selector(didTapPlayPause))
        playButtonTapGesture.allowedPressTypes = [NSNumber(value: UIPressType.playPause.rawValue as Int)];
        self.view.addGestureRecognizer(playButtonTapGesture)
    }
    
    func didTapPlayPause() {
        guard let videoViewController = self.viewControllers?.first as? VideoViewController else { return }
        videoViewController.togglePlayPause()
        // show/hide UI
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        Controller.fetchLiveVideos(channelId: channelId, config: sessionConfig)
            .start(on: QueueScheduler())
            .observe(on: UIScheduler())
            .startWithResult { [weak self] (result: Result<LiveVideosSearchResult, NSError>) in
                guard let this = self else { return }
                switch result {
                case .success(let searchResult):
                    let liveVideos = searchResult.liveVideos + searchResult.liveVideos + searchResult.liveVideos
                    this.viewData = .loaded(liveVideos)
                    guard let firstVideoInfo = liveVideos.first else { return }
                    let videoViewController = VideoViewController(videoInfo: firstVideoInfo, client: this.client)
                    this.setViewControllers([videoViewController], direction: .forward, animated: true, completion: nil)
                    videoViewController.loadVideo()
                    videoViewController.playVideo()
                case .failure(let error):
                    this.viewData = .errored(error)
                }
            }
        
        
    }
    
    private func videoInfoAfter(_ videoInfo: LiveVideoInfo) -> LiveVideoInfo? {
        switch viewData {
        case .loaded(let infos):
            guard let index = videoInfoIndex(videoInfo) else { return nil }
            let nextIndex = index + 1

    let channelId: String
    let sessionConfig: SessionConfig
    let client: XCDYouTubeClient
    
    let viewData: Property<PageViewData>
    let userPlayState = MutableProperty(UserPlayState.play)
    
    let fetchAction: Action<(), LiveVideosSearchResult, NSError>
    
    init(channelId: String, sessionConfig: SessionConfig, client: XCDYouTubeClient) {
        self.channelId = channelId
        self.sessionConfig = sessionConfig
        self.client = client
        
        fetchAction = Action { _ -> SignalProducer<LiveVideosSearchResult, NSError> in
            return Controller.fetchLiveVideos(channelId: channelId, config: sessionConfig)
                .start(on: QueueScheduler())
                .delay(5, on: QueueScheduler())
        }
    
        let loadings = fetchAction.isExecuting.signal.filter({ $0 }).map({ _ in PageViewData.loading })
        let errors = fetchAction.errors.map { PageViewData.failed($0) }
        let values = fetchAction.values.map { $0.liveVideos.count == 0 ? PageViewData.empty : PageViewData.loaded($0.liveVideos) }
        let merged = SignalProducer([loadings, errors, values]).flatten(.merge)
        self.viewData = ReactiveSwift.Property(initial: .unloaded, then: merged)
        
        super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        
        self.delegate = self
