Error with Plex component

I’m trying to setup the plex component but getting this error. Obviously it is related to the None being appeded to the URL but any ideas how I stop that happening?

2019-02-17 15:49:31 INFO (SyncWorker_7) [homeassistant.components.media_player.plex] Discovery configuration done (no token needed)
2019-02-17 15:49:32 INFO (SyncWorker_7) [homeassistant.components.media_player.plex] Discovery configuration done
2019-02-17 15:49:32 INFO (SyncWorker_7) [homeassistant.components.media_player.plex] Connected to: http://192.168.1.2:32400
2019-02-17 15:49:32 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.140206400884128] Error handling message: {‘type’: ‘call_service’, ‘domain’: ‘configurator’, ‘service’: ‘configure’, ‘service_data’: {‘configure_id’: ‘140206306599320-1’, ‘fields’: {‘token’: ‘my_token’}}, ‘id’: 15}
Traceback (most recent call last):
File “/srv/homeassistant/lib/python3.6/site-packages/requests/models.py”, line 379, in prepare_url
scheme, auth, host, port, path, query, fragment = parse_url(url)
File “/srv/homeassistant/lib/python3.6/site-packages/urllib3/util/url.py”, line 199, in parse_url
raise LocationParseError(url)
urllib3.exceptions.LocationParseError: Failed to parse: 192.168.1.2:32400None

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/websocket_api/decorators.py", line 17, in _handle_async_response
    await func(hass, connection, msg)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/websocket_api/commands.py", line 148, in handle_call_service
    connection.context(msg))
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/core.py", line 1130, in async_call
    self._execute_service(handler, service_call))
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/core.py", line 1152, in _execute_service
    await handler.func(service_call)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/configurator.py", line 221, in async_handle_service_call
    call.data.get(ATTR_FIELDS, {}))
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/media_player/plex.py", line 252, in plex_configuration_callback
    hass, config, add_entities_callback
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/media_player/plex.py", line 233, in setup_plexserver
    update_devices()
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 315, in wrapper
    result = method(*args, **kwargs)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/util/__init__.py", line 315, in wrapper
    result = method(*args, **kwargs)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/media_player/plex.py", line 169, in update_devices
    update_sessions)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/media_player/plex.py", line 323, in __init__
    self.refresh(device, session)
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/media_player/plex.py", line 421, in refresh
    self._set_media_type()
  File "/srv/homeassistant/lib/python3.6/site-packages/homeassistant/components/media_player/plex.py", line 473, in _set_media_type
    (self._session.season()).index).zfill(2)
  File "/srv/homeassistant/lib/python3.6/site-packages/plexapi/video.py", line 540, in season
    return self.fetchItem(self.parentKey)
  File "/srv/homeassistant/lib/python3.6/site-packages/plexapi/base.py", line 135, in fetchItem
    for elem in self._server.query(ekey):
  File "/srv/homeassistant/lib/python3.6/site-packages/plexapi/server.py", line 341, in query
    response = method(url, headers=headers, timeout=timeout, **kwargs)
  File "/srv/homeassistant/lib/python3.6/site-packages/requests/sessions.py", line 546, in get
    return self.request('GET', url, **kwargs)
  File "/srv/homeassistant/lib/python3.6/site-packages/requests/sessions.py", line 519, in request
    prep = self.prepare_request(req)
  File "/srv/homeassistant/lib/python3.6/site-packages/requests/sessions.py", line 462, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/srv/homeassistant/lib/python3.6/site-packages/requests/models.py", line 313, in prepare
    self.prepare_url(url, params)
  File "/srv/homeassistant/lib/python3.6/site-packages/requests/models.py", line 381, in prepare_url
    raise InvalidURL(*e.args)
requests.exceptions.InvalidURL: Failed to parse: 192.168.1.2:32400None

I’ve been seeing this same failure and I finally dug into it. The problem is that when seasons are hidden, Plex skips the season in the metadata chain for an episode. The Plex Hass component tries to get the season info like this:

if callable(self._session.season):
    self._media_season = str(
        (self._session.season()).index).zfill(2)
elif self._session.parentIndex is not None:
    self._media_season = self._session.parentIndex.zfill(2)
else:
    self._media_season = None

It unconditionally calls season(), which looks like this in plexapi:

def season(self):
    """" Return this episodes :func:`~plexapi.video.Season`.. """
    return self.fetchItem(self.parentKey)

If seasons are hidden, self.parentKey is None, which causes the malformed URL.

I think that plexapi should handle this condition without generating an exception, so I modified that function as follows:

def season(self):
    """" Return this episodes :func:`~plexapi.video.Season`.. """
    return None if self.parentKey is None else self.fetchItem(self.parentKey)

and the first function like this:

if self._session.parentKey is not None and callable(self._session.season):
    self._media_season = str(
        (self._session.season()).index).zfill(2)
elif self._session.parentIndex is not None:
    self._media_season = self._session.parentIndex.zfill(2)
else:
    self._media_season = None

No more exceptions now, and the season is properly populated via parentIndex. I wonder if a better solution is just to always use that, but I don’t know if there are other cases that I’m not considering.

The confusing part was that I already had seasons set to “show” for my TV Shows library, so I didn’t expect them to be hidden anywhere. It turns out that shows recorded via the DVR defaulted to “hide” for seasons (maybe an intentional default, or perhaps it was set that way before I changed the global default). In any case, “hide” makes more sense for DVR recordings in my opinion, so I just left it that way.

Hopefully all this helps someone. I’m using this change in a custom_component and with a custom plexapi dependency in Hass.io. An easier “no coding” solution is just to ensure that seasons are not hidden.

1 Like

Thanks for taking the time to post this. I ran into this exact issue, and this fixed it for me as well.My TV Show library was set to show seasons by default. However, I couldn’t find where the DVR defaulted recordings to hide as you describe above. So I hope they consider fixing this in HomeAssistant as you have done so here!

I am also seeing this issue and se no way to force plex to assign a season to DVR shows that do not have a season. I also have this issue with Movies as well, why would they have a Season? Has this issue been reported in HA as a bug? Seems like it has been around for a good bit.

Are there any other workaround beyond moving to a custom component?

Made two PRs that should hopefully address this:
https://github.com/home-assistant/home-assistant/pull/28708
https://github.com/home-assistant/home-assistant/pull/28709

Please let me know here (or there) if the problem persists after they’re released.