Move ffmpeg services to separate module (#146149)

* Move ffmpeg services to separate module

* Fix tests

* Rename
pull/140002/head^2
epenet 2025-06-05 14:39:44 +02:00 committed by GitHub
parent 9c23331ead
commit d6615e3d44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 89 additions and 61 deletions

View File

@ -11,32 +11,25 @@ from propcache.api import cached_property
import voluptuous as vol
from homeassistant.const import (
ATTR_ENTITY_ID,
CONTENT_TYPE_MULTIPART,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall, callback
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass
from homeassistant.util.signal_type import SignalType
from homeassistant.util.system_info import is_official_image
DOMAIN = "ffmpeg"
SERVICE_START = "start"
SERVICE_STOP = "stop"
SERVICE_RESTART = "restart"
SIGNAL_FFMPEG_START = SignalType[list[str] | None]("ffmpeg.start")
SIGNAL_FFMPEG_STOP = SignalType[list[str] | None]("ffmpeg.stop")
SIGNAL_FFMPEG_RESTART = SignalType[list[str] | None]("ffmpeg.restart")
from .const import (
DOMAIN,
SIGNAL_FFMPEG_RESTART,
SIGNAL_FFMPEG_START,
SIGNAL_FFMPEG_STOP,
)
from .services import async_setup_services
DATA_FFMPEG = "ffmpeg"
@ -63,8 +56,6 @@ CONFIG_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA,
)
SERVICE_FFMPEG_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the FFmpeg component."""
@ -74,29 +65,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
await manager.async_get_version()
# Register service
async def async_service_handle(service: ServiceCall) -> None:
"""Handle service ffmpeg process."""
entity_ids: list[str] | None = service.data.get(ATTR_ENTITY_ID)
if service.service == SERVICE_START:
async_dispatcher_send(hass, SIGNAL_FFMPEG_START, entity_ids)
elif service.service == SERVICE_STOP:
async_dispatcher_send(hass, SIGNAL_FFMPEG_STOP, entity_ids)
else:
async_dispatcher_send(hass, SIGNAL_FFMPEG_RESTART, entity_ids)
hass.services.async_register(
DOMAIN, SERVICE_START, async_service_handle, schema=SERVICE_FFMPEG_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_STOP, async_service_handle, schema=SERVICE_FFMPEG_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_RESTART, async_service_handle, schema=SERVICE_FFMPEG_SCHEMA
)
async_setup_services(hass)
hass.data[DATA_FFMPEG] = manager
return True

View File

@ -0,0 +1,9 @@
"""Support for FFmpeg."""
from homeassistant.util.signal_type import SignalType
DOMAIN = "ffmpeg"
SIGNAL_FFMPEG_START = SignalType[list[str] | None]("ffmpeg.start")
SIGNAL_FFMPEG_STOP = SignalType[list[str] | None]("ffmpeg.stop")
SIGNAL_FFMPEG_RESTART = SignalType[list[str] | None]("ffmpeg.restart")

View File

@ -0,0 +1,51 @@
"""Support for FFmpeg."""
from __future__ import annotations
import voluptuous as vol
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send
from .const import (
DOMAIN,
SIGNAL_FFMPEG_RESTART,
SIGNAL_FFMPEG_START,
SIGNAL_FFMPEG_STOP,
)
SERVICE_START = "start"
SERVICE_STOP = "stop"
SERVICE_RESTART = "restart"
SERVICE_FFMPEG_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})
async def _async_service_handle(service: ServiceCall) -> None:
"""Handle service ffmpeg process."""
entity_ids: list[str] | None = service.data.get(ATTR_ENTITY_ID)
if service.service == SERVICE_START:
async_dispatcher_send(service.hass, SIGNAL_FFMPEG_START, entity_ids)
elif service.service == SERVICE_STOP:
async_dispatcher_send(service.hass, SIGNAL_FFMPEG_STOP, entity_ids)
else:
async_dispatcher_send(service.hass, SIGNAL_FFMPEG_RESTART, entity_ids)
def async_setup_services(hass: HomeAssistant) -> None:
"""Register FFmpeg services."""
hass.services.async_register(
DOMAIN, SERVICE_START, _async_service_handle, schema=SERVICE_FFMPEG_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_STOP, _async_service_handle, schema=SERVICE_FFMPEG_SCHEMA
)
hass.services.async_register(
DOMAIN, SERVICE_RESTART, _async_service_handle, schema=SERVICE_FFMPEG_SCHEMA
)

View File

@ -3,12 +3,11 @@
from unittest.mock import AsyncMock, MagicMock, Mock, call, patch
from homeassistant.components import ffmpeg
from homeassistant.components.ffmpeg import (
DOMAIN,
from homeassistant.components.ffmpeg import DOMAIN, get_ffmpeg_manager
from homeassistant.components.ffmpeg.services import (
SERVICE_RESTART,
SERVICE_START,
SERVICE_STOP,
get_ffmpeg_manager,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
@ -85,7 +84,7 @@ class MockFFmpegDev(ffmpeg.FFmpegBase):
async def test_setup_component(hass: HomeAssistant) -> None:
"""Set up ffmpeg component."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
assert hass.data[ffmpeg.DATA_FFMPEG].binary == "ffmpeg"
@ -93,17 +92,17 @@ async def test_setup_component(hass: HomeAssistant) -> None:
async def test_setup_component_test_service(hass: HomeAssistant) -> None:
"""Set up ffmpeg component test services."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
assert hass.services.has_service(ffmpeg.DOMAIN, "start")
assert hass.services.has_service(ffmpeg.DOMAIN, "stop")
assert hass.services.has_service(ffmpeg.DOMAIN, "restart")
assert hass.services.has_service(DOMAIN, "start")
assert hass.services.has_service(DOMAIN, "stop")
assert hass.services.has_service(DOMAIN, "restart")
async def test_setup_component_test_register(hass: HomeAssistant) -> None:
"""Set up ffmpeg component test register."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
ffmpeg_dev = MockFFmpegDev(hass)
ffmpeg_dev._async_stop_ffmpeg = AsyncMock()
@ -122,7 +121,7 @@ async def test_setup_component_test_register(hass: HomeAssistant) -> None:
async def test_setup_component_test_register_no_startup(hass: HomeAssistant) -> None:
"""Set up ffmpeg component test register without startup."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
ffmpeg_dev = MockFFmpegDev(hass, False)
ffmpeg_dev._async_stop_ffmpeg = AsyncMock()
@ -141,7 +140,7 @@ async def test_setup_component_test_register_no_startup(hass: HomeAssistant) ->
async def test_setup_component_test_service_start(hass: HomeAssistant) -> None:
"""Set up ffmpeg component test service start."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
ffmpeg_dev = MockFFmpegDev(hass, False)
await ffmpeg_dev.async_added_to_hass()
@ -155,7 +154,7 @@ async def test_setup_component_test_service_start(hass: HomeAssistant) -> None:
async def test_setup_component_test_service_stop(hass: HomeAssistant) -> None:
"""Set up ffmpeg component test service stop."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
ffmpeg_dev = MockFFmpegDev(hass, False)
await ffmpeg_dev.async_added_to_hass()
@ -169,7 +168,7 @@ async def test_setup_component_test_service_stop(hass: HomeAssistant) -> None:
async def test_setup_component_test_service_restart(hass: HomeAssistant) -> None:
"""Set up ffmpeg component test service restart."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
ffmpeg_dev = MockFFmpegDev(hass, False)
await ffmpeg_dev.async_added_to_hass()
@ -186,7 +185,7 @@ async def test_setup_component_test_service_start_with_entity(
) -> None:
"""Set up ffmpeg component test service start."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
ffmpeg_dev = MockFFmpegDev(hass, False)
await ffmpeg_dev.async_added_to_hass()
@ -201,7 +200,7 @@ async def test_setup_component_test_service_start_with_entity(
async def test_async_get_image_with_width_height(hass: HomeAssistant) -> None:
"""Test fetching an image with a specific width and height."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
get_image_mock = AsyncMock()
with patch(
@ -220,7 +219,7 @@ async def test_async_get_image_with_extra_cmd_overlapping_width_height(
) -> None:
"""Test fetching an image with and extra_cmd with width and height and a specific width and height."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
get_image_mock = AsyncMock()
with patch(
@ -239,7 +238,7 @@ async def test_async_get_image_with_extra_cmd_overlapping_width_height(
async def test_async_get_image_with_extra_cmd_width_height(hass: HomeAssistant) -> None:
"""Test fetching an image with and extra_cmd and a specific width and height."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
get_image_mock = AsyncMock()
with patch(
@ -260,7 +259,7 @@ async def test_modern_ffmpeg(
) -> None:
"""Test modern ffmpeg uses the new ffmpeg content type."""
with assert_setup_component(1):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
manager = get_ffmpeg_manager(hass)
assert "ffmpeg" in manager.ffmpeg_stream_content_type
@ -277,7 +276,7 @@ async def test_legacy_ffmpeg(
),
patch("homeassistant.components.ffmpeg.is_official_image", return_value=False),
):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
manager = get_ffmpeg_manager(hass)
assert "ffserver" in manager.ffmpeg_stream_content_type
@ -291,7 +290,7 @@ async def test_ffmpeg_using_official_image(
assert_setup_component(1),
patch("homeassistant.components.ffmpeg.is_official_image", return_value=True),
):
await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
manager = get_ffmpeg_manager(hass)
assert "ffmpeg" in manager.ffmpeg_stream_content_type