|
2 | 2 |
|
3 | 3 | from functools import partial |
4 | 4 | import logging |
| 5 | +from typing import cast |
5 | 6 |
|
6 | 7 | import voluptuous as vol |
7 | 8 |
|
8 | 9 | from homeassistant.config_entries import ConfigEntryState |
9 | 10 | from homeassistant.const import CONF_ID |
10 | 11 | from homeassistant.core import HomeAssistant, ServiceCall, callback |
11 | | -from homeassistant.exceptions import HomeAssistantError |
| 12 | +from homeassistant.exceptions import ServiceValidationError |
12 | 13 | from homeassistant.helpers import config_validation as cv, selector |
13 | 14 |
|
14 | 15 | from .const import ( |
|
23 | 24 | SERVICE_START_TORRENT, |
24 | 25 | SERVICE_STOP_TORRENT, |
25 | 26 | ) |
26 | | -from .coordinator import TransmissionConfigEntry, TransmissionDataUpdateCoordinator |
| 27 | +from .coordinator import TransmissionDataUpdateCoordinator |
27 | 28 |
|
28 | 29 | _LOGGER = logging.getLogger(__name__) |
29 | 30 |
|
|
67 | 68 |
|
68 | 69 |
|
69 | 70 | def _get_coordinator_from_service_data( |
70 | | - hass: HomeAssistant, entry_id: str |
| 71 | + call: ServiceCall, |
71 | 72 | ) -> TransmissionDataUpdateCoordinator: |
72 | 73 | """Return coordinator for entry id.""" |
73 | | - entry: TransmissionConfigEntry | None = hass.config_entries.async_get_entry( |
74 | | - entry_id |
75 | | - ) |
76 | | - if entry is None or entry.state is not ConfigEntryState.LOADED: |
77 | | - raise HomeAssistantError(f"Config entry {entry_id} is not found or not loaded") |
78 | | - return entry.runtime_data |
| 74 | + config_entry_id: str = call.data[CONF_ENTRY_ID] |
| 75 | + if not (entry := call.hass.config_entries.async_get_entry(config_entry_id)): |
| 76 | + raise ServiceValidationError( |
| 77 | + translation_domain=DOMAIN, |
| 78 | + translation_key="integration_not_found", |
| 79 | + translation_placeholders={"target": DOMAIN}, |
| 80 | + ) |
| 81 | + if entry.state is not ConfigEntryState.LOADED: |
| 82 | + raise ServiceValidationError( |
| 83 | + translation_domain=DOMAIN, |
| 84 | + translation_key="not_loaded", |
| 85 | + translation_placeholders={"target": entry.title}, |
| 86 | + ) |
| 87 | + return cast(TransmissionDataUpdateCoordinator, entry.runtime_data) |
79 | 88 |
|
80 | 89 |
|
81 | 90 | async def _async_add_torrent(service: ServiceCall) -> None: |
82 | 91 | """Add new torrent to download.""" |
83 | | - entry_id: str = service.data[CONF_ENTRY_ID] |
84 | | - coordinator = _get_coordinator_from_service_data(service.hass, entry_id) |
| 92 | + coordinator = _get_coordinator_from_service_data(service) |
85 | 93 | torrent: str = service.data[ATTR_TORRENT] |
86 | 94 | download_path: str | None = service.data.get(ATTR_DOWNLOAD_PATH) |
87 | | - if torrent.startswith( |
88 | | - ("http", "ftp:", "magnet:") |
89 | | - ) or service.hass.config.is_allowed_path(torrent): |
90 | | - if download_path: |
91 | | - await service.hass.async_add_executor_job( |
92 | | - partial( |
93 | | - coordinator.api.add_torrent, torrent, download_dir=download_path |
94 | | - ) |
95 | | - ) |
96 | | - else: |
97 | | - await service.hass.async_add_executor_job( |
98 | | - coordinator.api.add_torrent, torrent |
99 | | - ) |
100 | | - await coordinator.async_request_refresh() |
| 95 | + |
| 96 | + if not ( |
| 97 | + torrent.startswith(("http", "ftp:", "magnet:")) |
| 98 | + or service.hass.config.is_allowed_path(torrent) |
| 99 | + ): |
| 100 | + raise ServiceValidationError( |
| 101 | + translation_domain=DOMAIN, |
| 102 | + translation_key="could_not_add_torrent", |
| 103 | + ) |
| 104 | + |
| 105 | + if download_path: |
| 106 | + await service.hass.async_add_executor_job( |
| 107 | + partial(coordinator.api.add_torrent, torrent, download_dir=download_path) |
| 108 | + ) |
101 | 109 | else: |
102 | | - _LOGGER.warning("Could not add torrent: unsupported type or no permission") |
| 110 | + await service.hass.async_add_executor_job(coordinator.api.add_torrent, torrent) |
| 111 | + await coordinator.async_request_refresh() |
103 | 112 |
|
104 | 113 |
|
105 | 114 | async def _async_start_torrent(service: ServiceCall) -> None: |
106 | 115 | """Start torrent.""" |
107 | | - entry_id: str = service.data[CONF_ENTRY_ID] |
108 | | - coordinator = _get_coordinator_from_service_data(service.hass, entry_id) |
| 116 | + coordinator = _get_coordinator_from_service_data(service) |
109 | 117 | torrent_id = service.data[CONF_ID] |
110 | 118 | await service.hass.async_add_executor_job(coordinator.api.start_torrent, torrent_id) |
111 | 119 | await coordinator.async_request_refresh() |
112 | 120 |
|
113 | 121 |
|
114 | 122 | async def _async_stop_torrent(service: ServiceCall) -> None: |
115 | 123 | """Stop torrent.""" |
116 | | - entry_id: str = service.data[CONF_ENTRY_ID] |
117 | | - coordinator = _get_coordinator_from_service_data(service.hass, entry_id) |
| 124 | + coordinator = _get_coordinator_from_service_data(service) |
118 | 125 | torrent_id = service.data[CONF_ID] |
119 | 126 | await service.hass.async_add_executor_job(coordinator.api.stop_torrent, torrent_id) |
120 | 127 | await coordinator.async_request_refresh() |
121 | 128 |
|
122 | 129 |
|
123 | 130 | async def _async_remove_torrent(service: ServiceCall) -> None: |
124 | 131 | """Remove torrent.""" |
125 | | - entry_id: str = service.data[CONF_ENTRY_ID] |
126 | | - coordinator = _get_coordinator_from_service_data(service.hass, entry_id) |
| 132 | + coordinator = _get_coordinator_from_service_data(service) |
127 | 133 | torrent_id = service.data[CONF_ID] |
128 | 134 | delete_data = service.data[ATTR_DELETE_DATA] |
129 | 135 | await service.hass.async_add_executor_job( |
|
0 commit comments