Skip to content

Commit

Permalink
Add support for total YouTube views (#123144)
Browse files Browse the repository at this point in the history
* Add support for retrieving the total views of a channel.

* Add missing tests

* Re-order imports

* Another run on code format

* Add missing translation

* Update YouTube test snapshots
  • Loading branch information
Alexwijn authored Sep 3, 2024
1 parent 8255728 commit 00533ba
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 1 deletion.
1 change: 1 addition & 0 deletions homeassistant/components/youtube/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
LOGGER = logging.getLogger(__package__)

ATTR_TITLE = "title"
ATTR_TOTAL_VIEWS = "total_views"
ATTR_LATEST_VIDEO = "latest_video"
ATTR_SUBSCRIBER_COUNT = "subscriber_count"
ATTR_DESCRIPTION = "description"
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/youtube/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
ATTR_SUBSCRIBER_COUNT,
ATTR_THUMBNAIL,
ATTR_TITLE,
ATTR_TOTAL_VIEWS,
ATTR_VIDEO_ID,
CONF_CHANNELS,
DOMAIN,
Expand Down Expand Up @@ -68,6 +69,7 @@ async def _async_update_data(self) -> dict[str, Any]:
ATTR_ICON: channel.snippet.thumbnails.get_highest_quality().url,
ATTR_LATEST_VIDEO: latest_video,
ATTR_SUBSCRIBER_COUNT: channel.statistics.subscriber_count,
ATTR_TOTAL_VIEWS: channel.statistics.view_count,
}
except UnauthorizedError as err:
raise ConfigEntryAuthFailed from err
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/youtube/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ATTR_SUBSCRIBER_COUNT,
ATTR_THUMBNAIL,
ATTR_TITLE,
ATTR_TOTAL_VIEWS,
ATTR_VIDEO_ID,
COORDINATOR,
DOMAIN,
Expand Down Expand Up @@ -58,6 +59,15 @@ class YouTubeSensorEntityDescription(SensorEntityDescription):
entity_picture_fn=lambda channel: channel[ATTR_ICON],
attributes_fn=None,
),
YouTubeSensorEntityDescription(
key="views",
translation_key="views",
native_unit_of_measurement="views",
available_fn=lambda _: True,
value_fn=lambda channel: channel[ATTR_TOTAL_VIEWS],
entity_picture_fn=lambda channel: channel[ATTR_ICON],
attributes_fn=None,
),
]


Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/youtube/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
"published_at": { "name": "Published at" }
}
},
"subscribers": { "name": "Subscribers" }
"subscribers": { "name": "Subscribers" },
"views": { "name": "Views" }
}
}
}
1 change: 1 addition & 0 deletions tests/components/youtube/snapshots/test_diagnostics.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
}),
'subscriber_count': 2290000,
'title': 'Google for Developers',
'total_views': 214141263,
}),
})
# ---
30 changes: 30 additions & 0 deletions tests/components/youtube/snapshots/test_sensor.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@
'state': '2290000',
})
# ---
# name: test_sensor.2
StateSnapshot({
'attributes': ReadOnlyDict({
'entity_picture': 'https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s800-c-k-c0x00ffffff-no-rj',
'friendly_name': 'Google for Developers Views',
'unit_of_measurement': 'views',
}),
'context': <ANY>,
'entity_id': 'sensor.google_for_developers_views',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '214141263',
})
# ---
# name: test_sensor_without_uploaded_video
StateSnapshot({
'attributes': ReadOnlyDict({
Expand Down Expand Up @@ -58,3 +73,18 @@
'state': '2290000',
})
# ---
# name: test_sensor_without_uploaded_video.2
StateSnapshot({
'attributes': ReadOnlyDict({
'entity_picture': 'https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s800-c-k-c0x00ffffff-no-rj',
'friendly_name': 'Google for Developers Views',
'unit_of_measurement': 'views',
}),
'context': <ANY>,
'entity_id': 'sensor.google_for_developers_views',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '214141263',
})
# ---
15 changes: 15 additions & 0 deletions tests/components/youtube/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ async def test_sensor(
state = hass.states.get("sensor.google_for_developers_subscribers")
assert state == snapshot

state = hass.states.get("sensor.google_for_developers_views")
assert state == snapshot


async def test_sensor_without_uploaded_video(
hass: HomeAssistant, snapshot: SnapshotAssertion, setup_integration: ComponentSetup
Expand All @@ -52,6 +55,9 @@ async def test_sensor_without_uploaded_video(
state = hass.states.get("sensor.google_for_developers_subscribers")
assert state == snapshot

state = hass.states.get("sensor.google_for_developers_views")
assert state == snapshot


async def test_sensor_updating(
hass: HomeAssistant, setup_integration: ComponentSetup
Expand Down Expand Up @@ -95,6 +101,9 @@ async def test_sensor_reauth_trigger(
state = hass.states.get("sensor.google_for_developers_subscribers")
assert state.state == "2290000"

state = hass.states.get("sensor.google_for_developers_views")
assert state.state == "214141263"

mock.set_thrown_exception(UnauthorizedError())
future = dt_util.utcnow() + timedelta(minutes=15)
async_fire_time_changed(hass, future)
Expand All @@ -121,6 +130,9 @@ async def test_sensor_unavailable(
state = hass.states.get("sensor.google_for_developers_subscribers")
assert state.state == "2290000"

state = hass.states.get("sensor.google_for_developers_views")
assert state.state == "214141263"

mock.set_thrown_exception(YouTubeBackendError())
future = dt_util.utcnow() + timedelta(minutes=15)
async_fire_time_changed(hass, future)
Expand All @@ -131,3 +143,6 @@ async def test_sensor_unavailable(

state = hass.states.get("sensor.google_for_developers_subscribers")
assert state.state == "unavailable"

state = hass.states.get("sensor.google_for_developers_views")
assert state.state == "unavailable"

0 comments on commit 00533ba

Please sign in to comment.