Skip to content

Commit 2bc8943

Browse files
authored
Merge pull request #106 from stridera/master
Better error handling and reconfiguration setup options.
2 parents 41f2297 + 9641771 commit 2bc8943

File tree

5 files changed

+118
-34
lines changed

5 files changed

+118
-34
lines changed

custom_components/plex_recently_added/config_flow.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
ConstantSelector,
1111
ConstantSelectorConfig
1212
)
13-
from homeassistant.config_entries import ConfigEntry
13+
from homeassistant.config_entries import ConfigEntry, ConfigFlowResult
1414
from homeassistant.core import callback
1515
from homeassistant.config_entries import ConfigFlow
1616
from homeassistant.const import (
@@ -89,4 +89,38 @@ async def async_step_user(
8989
return self.async_create_entry(title=user_input[CONF_NAME] if len(user_input[CONF_NAME]) > 0 else DEFAULT_NAME, data=user_input)
9090

9191
schema = self.add_suggested_values_to_schema(PLEX_SCHEMA, user_input)
92-
return self.async_show_form(step_id="user", data_schema=schema, errors=errors)
92+
return self.async_show_form(step_id="user", data_schema=schema, errors=errors)
93+
94+
async def async_step_reconfigure(
95+
self, user_input: dict[str, Any] | None = None
96+
) -> ConfigFlowResult:
97+
"""Handle reconfiguration of the integration."""
98+
errors = {}
99+
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
100+
101+
if user_input is not None:
102+
try:
103+
await setup_client(
104+
self.hass,
105+
user_input[CONF_NAME],
106+
user_input[CONF_SSL],
107+
user_input[CONF_API_KEY],
108+
user_input[CONF_MAX],
109+
user_input[CONF_ON_DECK],
110+
user_input[CONF_HOST],
111+
user_input[CONF_PORT],
112+
user_input.get(CONF_SECTION_TYPES, []),
113+
user_input.get(CONF_SECTION_LIBRARIES, []),
114+
user_input.get(CONF_EXCLUDE_KEYWORDS, []),
115+
)
116+
except FailedToLogin as err:
117+
errors = {'base': 'failed_to_login'}
118+
else:
119+
return self.async_update_reload_and_abort(
120+
entry,
121+
data={**entry.data, **user_input},
122+
reason="reconfigure_successful"
123+
)
124+
125+
schema = self.add_suggested_values_to_schema(PLEX_SCHEMA, entry.data)
126+
return self.async_show_form(step_id="reconfigure", data_schema=schema, errors=errors)

custom_components/plex_recently_added/options_flow.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def __init__(self, config_entry: ConfigEntry) -> None:
3232
async def async_step_init(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
3333
errors = {}
3434

35+
# Check if the integration is loaded and coordinator is available
36+
if DOMAIN not in self.hass.data or self._config_entry.entry_id not in self.hass.data[DOMAIN]:
37+
return self.async_abort(reason="integration_not_loaded")
38+
3539
coordinator = self.hass.data[DOMAIN][self._config_entry.entry_id]
3640

3741
if user_input is not None:

custom_components/plex_recently_added/plex_api.py

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async def update(self):
5050
try:
5151
info_res = await self._hass.async_add_executor_job(
5252
requests.get,
53-
f'{info_url}?X-Plex-Token={self._token}',
53+
f'{info_url}?X-Plex-Token={self._token}',
5454
{
5555
"headers":{
5656
"User-agent": USER_AGENT,
@@ -62,8 +62,8 @@ async def update(self):
6262
check_headers(info_res)
6363
root = ElementTree.fromstring(info_res.text)
6464
identifier = root.get("machineIdentifier")
65-
except OSError as e:
66-
raise FailedToLogin
65+
except (OSError, ValueError) as e:
66+
raise FailedToLogin from e
6767

6868
url_base = f'{info_url}/library/sections'
6969
all_libraries = f'{url_base}/all'
@@ -76,7 +76,7 @@ async def update(self):
7676
try:
7777
libraries = await self._hass.async_add_executor_job(
7878
requests.get,
79-
f'{all_libraries}?X-Plex-Token={self._token}',
79+
f'{all_libraries}?X-Plex-Token={self._token}',
8080
{
8181
"headers":{
8282
"User-agent": USER_AGENT,
@@ -91,8 +91,8 @@ async def update(self):
9191
libs.append(lib.get("title"))
9292
if lib.get("type") in self._section_types and (len(self._section_libraries) == 0 or lib.get("title") in self._section_libraries):
9393
sections.append({'type': lib.get("type"),'key': lib.get("key")})
94-
except OSError as e:
95-
raise FailedToLogin
94+
except (OSError, ValueError) as e:
95+
raise FailedToLogin from e
9696

9797
""" Looping through all libraries (sections) """
9898
data = {
@@ -102,30 +102,34 @@ async def update(self):
102102
data[s] = []
103103

104104
for library in sections:
105-
recent_or_deck = on_deck if self._on_deck else recently_added
106-
sub_sec = await self._hass.async_add_executor_job(
107-
requests.get,
108-
f'{recent_or_deck.format(library["key"], self._max * 2)}&X-Plex-Token={self._token}',
109-
{
110-
"headers":{
111-
"User-agent": USER_AGENT,
112-
"Accept": ACCEPTS,
113-
},
114-
"timeout":10
115-
}
116-
)
117-
check_headers(sub_sec)
118-
root = ElementTree.fromstring(sub_sec.text)
119-
parsed_libs = parse_library(root)
120-
121-
# Fetch trailer URLs for each item
122-
for item in parsed_libs:
123-
item['trailer'] = await get_tmdb_trailer_url(self._hass, item['title'], library['type'])
124-
125-
if library["type"] not in data['all']:
126-
data['all'][library["type"]] = []
127-
data['all'][library["type"]] += parsed_libs
128-
data[library["type"]] += parsed_libs
105+
try:
106+
recent_or_deck = on_deck if self._on_deck else recently_added
107+
sub_sec = await self._hass.async_add_executor_job(
108+
requests.get,
109+
f'{recent_or_deck.format(library["key"], self._max * 2)}&X-Plex-Token={self._token}',
110+
{
111+
"headers":{
112+
"User-agent": USER_AGENT,
113+
"Accept": ACCEPTS,
114+
},
115+
"timeout":10
116+
}
117+
)
118+
check_headers(sub_sec)
119+
root = ElementTree.fromstring(sub_sec.text)
120+
parsed_libs = parse_library(root)
121+
122+
# Fetch trailer URLs for each item
123+
for item in parsed_libs:
124+
item['trailer'] = await get_tmdb_trailer_url(self._hass, item['title'], library['type'])
125+
126+
if library["type"] not in data['all']:
127+
data['all'][library["type"]] = []
128+
data['all'][library["type"]] += parsed_libs
129+
data[library["type"]] += parsed_libs
130+
except (OSError, ValueError) as e:
131+
# Skip this library if it fails to load
132+
continue
129133

130134
data_out = {}
131135
for k in data.keys():

custom_components/plex_recently_added/strings.json

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@
1515
"section_libraries": "Which libraries to consider",
1616
"verify_ssl": "Verify SSL"
1717
}
18+
},
19+
"reconfigure": {
20+
"title": "Reconfigure Plex Recently Added",
21+
"description": "Update your Plex server connection settings",
22+
"data": {
23+
"name": "Name",
24+
"host": "Plex address",
25+
"port": "Plex port",
26+
"api_key": "Plex token",
27+
"ssl": "SSL",
28+
"max": "Max number of items in sensor",
29+
"on_deck": "Show \"on deck\" items",
30+
"section_types": "Which section types to consider",
31+
"exclude_keywords": "Keyword to be exclude from the sensor",
32+
"section_libraries": "Which libraries to consider",
33+
"verify_ssl": "Verify SSL"
34+
}
1835
}
1936
},
2037
"error": {
@@ -24,7 +41,8 @@
2441
"abort": {
2542
"already_configured": "User is already configured (check README)",
2643
"failed_to_login": "Failed to Log-in",
27-
"cannot_be_reached": "Plex cannot be reached"
44+
"cannot_be_reached": "Plex cannot be reached",
45+
"reconfigure_successful": "Reconfiguration successful"
2846
}
2947
},
3048
"options": {
@@ -38,6 +56,9 @@
3856
"on_deck": "Show \"on deck\" items"
3957
}
4058
}
59+
},
60+
"abort": {
61+
"integration_not_loaded": "Integration is not loaded. Please reload the integration and try again."
4162
}
4263
}
4364
}

custom_components/plex_recently_added/translations/en.json

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@
1515
"section_libraries": "Which libraries to consider",
1616
"verify_ssl": "Verify SSL"
1717
}
18+
},
19+
"reconfigure": {
20+
"title": "Reconfigure Plex Recently Added",
21+
"description": "Update your Plex server connection settings",
22+
"data": {
23+
"name": "Name",
24+
"host": "Plex address",
25+
"port": "Plex port",
26+
"api_key": "Plex token",
27+
"ssl": "SSL",
28+
"max": "Max number of items in sensor",
29+
"on_deck": "Show \"on deck\" items",
30+
"section_types": "Which section types to consider",
31+
"exclude_keywords": "Keyword to be exclude from the sensor",
32+
"section_libraries": "Which libraries to consider",
33+
"verify_ssl": "Verify SSL"
34+
}
1835
}
1936
},
2037
"error": {
@@ -24,7 +41,8 @@
2441
"abort": {
2542
"already_configured": "User is already configured (check README)",
2643
"failed_to_login": "Failed to Log-in",
27-
"cannot_be_reached": "Plex cannot be reached"
44+
"cannot_be_reached": "Plex cannot be reached",
45+
"reconfigure_successful": "Reconfiguration successful"
2846
}
2947
},
3048
"options": {
@@ -38,6 +56,9 @@
3856
"on_deck": "Show \"on deck\" items"
3957
}
4058
}
59+
},
60+
"abort": {
61+
"integration_not_loaded": "Integration is not loaded. Please reload the integration and try again."
4162
}
4263
}
4364
}

0 commit comments

Comments
 (0)