From 2b3caa716a66075543856382056fafa72d3718df Mon Sep 17 00:00:00 2001
From: Paulus Schoutsen <paulus@paulusschoutsen.nl>
Date: Sun, 4 Dec 2016 15:30:55 -0800
Subject: [PATCH] Cast progress (#4735)

* add progress to google cast

* Add progress to media player demo
---
 homeassistant/components/media_player/cast.py | 27 ++++++++
 homeassistant/components/media_player/demo.py | 68 ++++++++++++++-----
 2 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py
index 1d01f0058ec..0f3b98cab46 100644
--- a/homeassistant/components/media_player/cast.py
+++ b/homeassistant/components/media_player/cast.py
@@ -18,6 +18,7 @@ from homeassistant.const import (
     CONF_HOST, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING,
     STATE_UNKNOWN)
 import homeassistant.helpers.config_validation as cv
+import homeassistant.util.dt as dt_util
 
 REQUIREMENTS = ['pychromecast==0.7.6']
 
@@ -105,6 +106,7 @@ class CastDevice(MediaPlayerDevice):
 
         self.cast_status = self.cast.status
         self.media_status = self.cast.media_controller.status
+        self.media_status_received = None
 
     @property
     def should_poll(self):
@@ -231,6 +233,30 @@ class CastDevice(MediaPlayerDevice):
         """Flag of media commands that are supported."""
         return SUPPORT_CAST
 
+    @property
+    def media_position(self):
+        """Position of current playing media in seconds."""
+        if self.media_status is None or not (
+                self.media_status.player_is_playing or
+                self.media_status.player_is_idle):
+            return None
+
+        position = self.media_status.current_time
+
+        if self.media_status.player_is_playing:
+            position += (dt_util.utcnow() -
+                         self.media_status_received).total_seconds()
+
+        return position
+
+    @property
+    def media_position_updated_at(self):
+        """When was the position of the current playing media valid.
+
+        Returns value from homeassistant.util.dt.utcnow().
+        """
+        return self.media_status_received
+
     def turn_on(self):
         """Turn on the ChromeCast."""
         # The only way we can turn the Chromecast is on is by launching an app
@@ -292,4 +318,5 @@ class CastDevice(MediaPlayerDevice):
     def new_media_status(self, status):
         """Called when a new media status is received."""
         self.media_status = status
+        self.media_status_received = dt_util.utcnow()
         self.schedule_update_ha_state()
diff --git a/homeassistant/components/media_player/demo.py b/homeassistant/components/media_player/demo.py
index 1c1687de319..226ddfe4769 100644
--- a/homeassistant/components/media_player/demo.py
+++ b/homeassistant/components/media_player/demo.py
@@ -10,6 +10,7 @@ from homeassistant.components.media_player import (
     SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
     SUPPORT_SELECT_SOURCE, SUPPORT_CLEAR_PLAYLIST, MediaPlayerDevice)
 from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING
+import homeassistant.util.dt as dt_util
 
 
 # pylint: disable=unused-argument
@@ -18,8 +19,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
     add_devices([
         DemoYoutubePlayer(
             'Living Room', 'eyU3bRy2x44',
-            '♥♥ The Best Fireplace Video (3 hours)'),
-        DemoYoutubePlayer('Bedroom', 'kxopViU98Xo', 'Epic sax guy 10 hours'),
+            '♥♥ The Best Fireplace Video (3 hours)', 300),
+        DemoYoutubePlayer('Bedroom', 'kxopViU98Xo', 'Epic sax guy 10 hours',
+                          360000),
         DemoMusicPlayer(), DemoTVShowPlayer(),
     ])
 
@@ -78,32 +80,32 @@ class AbstractDemoPlayer(MediaPlayerDevice):
     def turn_on(self):
         """Turn the media player on."""
         self._player_state = STATE_PLAYING
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
     def turn_off(self):
         """Turn the media player off."""
         self._player_state = STATE_OFF
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
     def mute_volume(self, mute):
         """Mute the volume."""
         self._volume_muted = mute
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
     def set_volume_level(self, volume):
         """Set the volume level, range 0..1."""
         self._volume_level = volume
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
     def media_play(self):
         """Send play command."""
         self._player_state = STATE_PLAYING
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
     def media_pause(self):
         """Send pause command."""
         self._player_state = STATE_PAUSED
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
 
 class DemoYoutubePlayer(AbstractDemoPlayer):
@@ -111,11 +113,14 @@ class DemoYoutubePlayer(AbstractDemoPlayer):
 
     # We only implement the methods that we support
 
-    def __init__(self, name, youtube_id=None, media_title=None):
+    def __init__(self, name, youtube_id=None, media_title=None, duration=360):
         """Initialize the demo device."""
         super().__init__(name)
         self.youtube_id = youtube_id
         self._media_title = media_title
+        self._duration = duration
+        self._progress = int(duration * .15)
+        self._progress_updated_at = dt_util.utcnow()
 
     @property
     def media_content_id(self):
@@ -130,7 +135,7 @@ class DemoYoutubePlayer(AbstractDemoPlayer):
     @property
     def media_duration(self):
         """Return the duration of current playing media in seconds."""
-        return 360
+        return self._duration
 
     @property
     def media_image_url(self):
@@ -152,10 +157,39 @@ class DemoYoutubePlayer(AbstractDemoPlayer):
         """Flag of media commands that are supported."""
         return YOUTUBE_PLAYER_SUPPORT
 
+    @property
+    def media_position(self):
+        """Position of current playing media in seconds."""
+        if self._progress is None:
+            return None
+
+        position = self._progress
+
+        if self._player_state == STATE_PLAYING:
+            position += (dt_util.utcnow() -
+                         self._progress_updated_at).total_seconds()
+
+        return position
+
+    @property
+    def media_position_updated_at(self):
+        """When was the position of the current playing media valid.
+
+        Returns value from homeassistant.util.dt.utcnow().
+        """
+        if self._player_state == STATE_PLAYING:
+            return self._progress_updated_at
+
     def play_media(self, media_type, media_id, **kwargs):
         """Play a piece of media."""
         self.youtube_id = media_id
-        self.update_ha_state()
+        self.schedule_update_ha_state()
+
+    def media_pause(self):
+        """Send pause command."""
+        self._progress = self.media_position
+        self._progress_updated_at = dt_util.utcnow()
+        super().media_pause()
 
 
 class DemoMusicPlayer(AbstractDemoPlayer):
@@ -249,20 +283,20 @@ class DemoMusicPlayer(AbstractDemoPlayer):
         """Send previous track command."""
         if self._cur_track > 0:
             self._cur_track -= 1
-            self.update_ha_state()
+            self.schedule_update_ha_state()
 
     def media_next_track(self):
         """Send next track command."""
         if self._cur_track < len(self.tracks) - 1:
             self._cur_track += 1
-            self.update_ha_state()
+            self.schedule_update_ha_state()
 
     def clear_playlist(self):
         """Clear players playlist."""
         self.tracks = []
         self._cur_track = 0
         self._player_state = STATE_OFF
-        self.update_ha_state()
+        self.schedule_update_ha_state()
 
 
 class DemoTVShowPlayer(AbstractDemoPlayer):
@@ -344,15 +378,15 @@ class DemoTVShowPlayer(AbstractDemoPlayer):
         """Send previous track command."""
         if self._cur_episode > 1:
             self._cur_episode -= 1
-            self.update_ha_state()
+            self.schedule_update_ha_state()
 
     def media_next_track(self):
         """Send next track command."""
         if self._cur_episode < self._episode_count:
             self._cur_episode += 1
-            self.update_ha_state()
+            self.schedule_update_ha_state()
 
     def select_source(self, source):
         """Set the input source."""
         self._source = source
-        self.update_ha_state()
+        self.schedule_update_ha_state()
-- 
GitLab