Show all YouTube subscriptions in config flow (#94287)

This commit is contained in:
Joost Lekkerkerker 2023-06-27 20:07:44 +02:00 committed by GitHub
parent 48776f86dc
commit 6a85e227db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 20 deletions

View File

@ -1,7 +1,7 @@
"""Config flow for YouTube integration."""
from __future__ import annotations
from collections.abc import Mapping
from collections.abc import AsyncGenerator, Mapping
import logging
from typing import Any
@ -31,6 +31,24 @@ from .const import (
)
async def _get_subscriptions(hass: HomeAssistant, resource: Resource) -> AsyncGenerator:
amount_of_subscriptions = 50
received_amount_of_subscriptions = 0
next_page_token = None
while received_amount_of_subscriptions < amount_of_subscriptions:
# pylint: disable=no-member
subscription_request: HttpRequest = resource.subscriptions().list(
part="snippet", mine=True, maxResults=50, pageToken=next_page_token
)
res = await hass.async_add_executor_job(subscription_request.execute)
amount_of_subscriptions = res["pageInfo"]["totalResults"]
if "nextPageToken" in res:
next_page_token = res["nextPageToken"]
for item in res["items"]:
received_amount_of_subscriptions += 1
yield item
async def get_resource(hass: HomeAssistant, token: str) -> Resource:
"""Get Youtube resource async."""
@ -152,17 +170,12 @@ class OAuth2FlowHandler(
service = await get_resource(
self.hass, self._data[CONF_TOKEN][CONF_ACCESS_TOKEN]
)
# pylint: disable=no-member
subscription_request: HttpRequest = service.subscriptions().list(
part="snippet", mine=True, maxResults=50
)
response = await self.hass.async_add_executor_job(subscription_request.execute)
selectable_channels = [
SelectOptionDict(
value=subscription["snippet"]["resourceId"]["channelId"],
label=subscription["snippet"]["title"],
)
for subscription in response["items"]
async for subscription in _get_subscriptions(self.hass, service)
]
return self.async_show_form(
step_id="channels",
@ -191,17 +204,12 @@ class YouTubeOptionsFlowHandler(OptionsFlowWithConfigEntry):
service = await get_resource(
self.hass, self.config_entry.data[CONF_TOKEN][CONF_ACCESS_TOKEN]
)
# pylint: disable=no-member
subscription_request: HttpRequest = service.subscriptions().list(
part="snippet", mine=True, maxResults=50
)
response = await self.hass.async_add_executor_job(subscription_request.execute)
selectable_channels = [
SelectOptionDict(
value=subscription["snippet"]["resourceId"]["channelId"],
label=subscription["snippet"]["title"],
)
for subscription in response["items"]
async for subscription in _get_subscriptions(self.hass, service)
]
return self.async_show_form(
step_id="init",

View File

@ -53,16 +53,31 @@ class YouTubeDataUpdateCoordinator(DataUpdateCoordinator):
async def _async_update_data(self) -> dict[str, Any]:
service = await self._auth.get_resource()
channels = self.config_entry.options[CONF_CHANNELS]
channel_request: HttpRequest = service.channels().list(
part="snippet,statistics", id=",".join(channels), maxResults=50
)
response: dict = await self.hass.async_add_executor_job(channel_request.execute)
channels = await self._get_channels(service)
return await self.hass.async_add_executor_job(
self._get_channel_data, service, response["items"]
self._get_channel_data, service, channels
)
async def _get_channels(self, service: Resource) -> list[dict[str, Any]]:
data = []
received_channels = 0
channels = self.config_entry.options[CONF_CHANNELS]
while received_channels < len(channels):
# We're slicing the channels in chunks of 50 to avoid making the URI too long
end = min(received_channels + 50, len(channels) - 1)
channel_request: HttpRequest = service.channels().list(
part="snippet,statistics",
id=",".join(channels[received_channels:end]),
maxResults=50,
)
response: dict = await self.hass.async_add_executor_job(
channel_request.execute
)
data.extend(response["items"])
received_channels += len(response["items"])
return data
def _get_channel_data(
self, service: Resource, channels: list[dict[str, Any]]
) -> dict[str, Any]:

View File

@ -59,7 +59,13 @@ class MockSubscriptions:
"""Initialize mock subscriptions."""
self._fixture = fixture
def list(self, part: str, mine: bool, maxResults: int | None = None) -> MockRequest:
def list(
self,
part: str,
mine: bool,
maxResults: int | None = None,
pageToken: str | None = None,
) -> MockRequest:
"""Return a fixture."""
return MockRequest(fixture=self._fixture)