Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for non-clients, NVidia shield, dynamic grouping, extra metad… #6054

Merged
merged 25 commits into from
Mar 16, 2017
Merged

Support for non-clients, NVidia shield, dynamic grouping, extra metad… #6054

merged 25 commits into from
Mar 16, 2017

Conversation

JesseWebDotCom
Copy link
Contributor

This is my first contribution so forgive me if I misstep.

A full breakdown of the updates are here:

If you agree with the direction and or changes, I can start drafting the updated version of:
https://home-assistant.io/components/media_player.plex/

Let me know if there is an official process for updating documentation
Thanks

@homeassistant
Copy link
Contributor

Hi @JesseWebDotCom,

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

# or when casting to an Nvidia shield running a plex server
if self.local:
return None
#No mute since Shield only supports volume 2-100

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block comment should start with '# '

thumb_response = requests.get(thumb_url, verify=False)
if thumb_response.status_code != 200:
_LOGGER.debug(
'Using art because thumbnail was not found: content id %s',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (83 > 79 characters)

@@ -62,6 +91,17 @@ def config_from_file(filename, config=None):

def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Setup the Plex platform."""

#optional parameters

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block comment should start with '# '

from homeassistant.loader import get_component
from homeassistant.helpers.event import (track_utc_time_change)
import homeassistant.helpers.config_validation as cv

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module level import not at top of file

STATE_UNKNOWN)
SUPPORT_PLAY, SUPPORT_VOLUME_MUTE, SUPPORT_TURN_OFF, SUPPORT_SEEK,
PLATFORM_SCHEMA, MediaPlayerDevice)
from homeassistant.const import (DEVICE_DEFAULT_NAME, STATE_IDLE, STATE_OFF,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module level import not at top of file
'homeassistant.const.STATE_UNKNOWN' imported but unused

import json
import logging
import os
from datetime import timedelta
from urllib.parse import urlparse

import voluptuous as vol

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module level import not at top of file

from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

import asyncio

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module level import not at top of file

@JesseWebDotCom
Copy link
Contributor Author

I can't sign the CLA - the web page spinner never stops (tried from multiple browsers, clients, and networks).

@robbiet480
Copy link
Member

@JesseWebDotCom Can you provide a full list of changes?

@JesseWebDotCom
Copy link
Contributor Author

My original documentation is here:
https://github.com/JesseWebDotCom/home-assistant-configuration/blob/master/docs/media_player_plexdevices.md

change log (hopefully that’s everything):

  • Improved compatibility
    • Added support for non-clients
      • remote users
      • PlexConnect Apple TV’s
      • Other non-controllable clients
    • Improved support for channels (displays and is controllable providing the channel session closely resembles a movie or TV session)
  • Improved controls
    • Added volume controls (volume up/down, mute)
      • Faking starting volume (as 100) as plexapi does not expose current volume
      • Faking muting as plexapi does not expose mute state
    • Added Off
      • Faking by stopping media as plexapi does not provide an off method
    • Added progress bar
    • Restrict controls based on identified compatibility issues:
      • Remove controls if client is local (i.e. loopback with no controllable IP)
      • Remove mute for Nvidia shields (they do not support volume lower than 2)
    • Added ability (enabled through optional config) to avoid control restriction and always show all controls
  • Improved metadata
    • Display library name in “app_name” attribute
    • Display movie name as “name (year)”, ex: “Blair Witch (2016)”
    • Display TV show and episode number with leading 0 (ex. S02 instead of S2)
    • Display music artist
    • All music attributes (media artist, album name, album artist, track number)
      • Fallback to Album artist is media artist is blank
    • Media position and duration attributes
    • Added fallback to display TV season number when API seasons() call fails
    • Added ability (enabled through optional config) to display the thumbnail for the playing TV episode as opposed to the show
    • Display art if thumbnail is non-existent (useful for tv/movies without posters)
  • Added ability (enabled through optional config) to have entity ID’s named media_player.{plex player id} instead of media_player.{plex player name}.
  • Added PlayMedia service abilities to make a plex client play a movie, tv show, or music playlist
  • (enabled through optional config) Added dynamic “active” and “inactive” groups
    • I’d like to establish a pattern here for automated grouping and to avoid conflicts with manual grouping. I chose to prefix my automated group names with underscores.
    • There has to be some problem with how I created the groups as when I run this “{{ states.group._plex_devices_disconnected.attributes.entity_id | length }}” I get this “Error rendering template: SecurityError: access to attribute '_plex_devices_disconnected' of 'DomainStates' object is unsafe.”
  • Added optional config parameters (not sure I did this right but it works) to do the following:
    • 'include_non_clients’: includes non-controllable clients (ex. PlexConnect Apple TV’s), defaults to false (for backwards compatibility)
    • 'use_episode_art’: Use episode art instead of show art, defaults to false (for backwards compatibility)
    • 'use_dynamic_groups’: Automatically group devices into active and inactive groups, defaults to false (for backwards compatibility)
    • 'use_custom_entity_ids’: Name entities by device id (less ambiguous, more predictable names), defaults to false (for backwards compatibility)
    • 'show_all_controls’: Always show all controls instead of only displaying ones within client capabilities, defaults to false (for backwards compatibility)
  • Misc improvements
    • Improved refresh speed by querying sessions first, devices second
    • Improved state accuracy by forcing idle status for old/invalid sessions
    • Improved error avoidance by checking if object’s are not none and if they are callable
    • Fixed bug where TV season would display even though device has gone idle
    • Removed unnecessary code:
      • Removed “return STATE_UNKNON” code as it was unreachable
      • Removed “import Show” references as we already know the media type

# with a loopback address, the device must be local or casting
for client in self.device.server.clients():
if "127.0.0.1" in client.baseurl:
if client.machineIdentifier == self.device.machineIdentifier:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (81 > 79 characters)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more readable on one line but I'll change it if you need me to.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do, as we have strict requirements on PEP8 compliance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so I'm not sure how to fix this as I got an auto message each way I went

for client in self.device.server.clients():
if "127.0.0.1" in client.baseurl:
if client.machineIdentifier == \
self.device.machineIdentifier:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line with same indent as next logical line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boo, will fix (hopefully)

for client in self.device.server.clients():
if "127.0.0.1" in client.baseurl:
if client.machineIdentifier == \
self.device.machineIdentifier:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line missing indentation or outdented

@robbiet480
Copy link
Member

@JesseWebDotCom You can use pylint and flake8 locally before pushing changes to ensure you are PEP8 compliant.

@JesseWebDotCom
Copy link
Contributor Author

Thanks. Already use pylint in Atom.io combined with Atom beautify using yapf. It usually fixes everything automatically. Just added flake8 for good measure.

@JesseWebDotCom
Copy link
Contributor Author

JesseWebDotCom commented Feb 19, 2017

Never mind, I see how to update the documentation. I'll start doing that now and submit for review.

@fabaff
Copy link
Member

fabaff commented Feb 20, 2017

>>>>>>> 4201005ca8ff3f7b584e5cbb9f3464f65c8ce2a9

# set groups with updated memberships
set_group_members(hass, GROUP_ACTIVE_DEVICES,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexpected indentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore, I pushed a new update (fix3) that works and doesn't include the junk text above

active_entity_id_list.append(client.entity_id)
>>>>>>> 4201005ca8ff3f7b584e5cbb9f3464f65c8ce2a9

# set groups with updated memberships

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexpected indentation (comment)

inactive_entity_id_list.append(client.entity_id)
else:
active_entity_id_list.append(client.entity_id)
>>>>>>> 4201005ca8ff3f7b584e5cbb9f3464f65c8ce2a9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace around operator

else:
active_entity_id_list.append(client.entity_id)
=======
if not client.hidden:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexpected indentation

client.entity_id)
else:
active_entity_id_list.append(client.entity_id)
=======

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace around operator

if client.entity_id:
<<<<<<< HEAD
# do not add if hidden
client_states = hass.states.get(client.entity_id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexpected indentation

for machine_identifier, client in plex_clients.items():
if client.entity_id:
<<<<<<< HEAD
# do not add if hidden

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexpected indentation (comment)


for machine_identifier, client in plex_clients.items():
if client.entity_id:
<<<<<<< HEAD

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines after class or function definition, found 0
expected an indented block
IndentationError: expected an indented block
missing whitespace around bitwise or shift operator
missing whitespace around operator

@JesseWebDotCom
Copy link
Contributor Author

Any word on when this and the documentation (home-assistant/home-assistant.io#2094) will get officially incorporated?

if self.session and self.session.player:
if ((frozen_seconds >
int(self.optional_config[CONF_MAX_FROZEN_PAUSED])) and
(self.session.player.state == 'paused' or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need one space here.

@arsaboo
Copy link
Contributor

arsaboo commented Feb 26, 2017

@JesseWebDotCom Looks like the build is failing.....there are some simple errors that can be fixed.


def set_group_members(hass, group_entity_id, member_entity_id_list):
"""Creates group if doesn't exist and sets memberships"""
Copy link
Contributor

@arsaboo arsaboo Feb 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to end in a period
"""Create group if doesn't exist and set memberships."""

self.name.lower().replace('-', '_'))

def refresh(self, device, session):
"""Refresh key device data"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""Refresh key device data."""

self._make = make

def force_idle(self):
"""Force client to idle"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""Force client to idle."""


@property
def app_name(self):
"""Library name of playing media"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""Return the library name of playing media."""

@Teagan42
Copy link
Contributor

I'm still getting a session based client and a regular client from the server.clients.

@JesseWebDotCom
Copy link
Contributor Author

JesseWebDotCom commented Mar 15, 2017

@Teagan42 - what's your recommendation? Also, how can I replicate this?

SUPPORT_TURN_OFF | SUPPORT_VOLUME_MUTE)

# only show controls when we know what device is connecting
if not self._make:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be an elif? It's overwriting the two ifs before this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, those are missing return statements - will add

if config.get(CONF_INCLUDE_NON_CLIENTS):
for machine_identifier, session in plex_sessions.items():
if (machine_identifier not in plex_clients
and machine_identifier is not None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be to prevent dupes:

and session.player.machineIdentifier is not None):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add, test, and check in (for this one spot) - thanks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup this fixes dupe issue

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so this is odd - at first load, with this change, I don't get dupes, but after it sits for a bit, I get dupes... let me investigate more...

@Teagan42
Copy link
Contributor

@JesseWebDotCom I'm not sure what is causing duplicate clients, I'm still digging.

@JesseWebDotCom
Copy link
Contributor Author

@Teagan42 - Standing by

@Teagan42
Copy link
Contributor

So, I added the machine identifier to the state attributes - when it first loads, only the first two show up (yay), but after another pass, the second two show up (empty machine identifiers)

media_player.my_afts	idle	machineIdentifer: ead79392dc1a30ac-com-plexapp-android
app_name: 
friendly_name: My AFTS
media_player.my_afts_2	idle	machineIdentifer: 48d04c6c0bf62ed0-com-plexapp-android
app_name: 
friendly_name: My AFTS
media_player.my_afts_3	idle	supported_features: 20533
friendly_name: My AFTS
media_player.my_afts_4	idle	supported_features: 20533
friendly_name: My AFTS

So, some how, we're getting empty machine identifiers into the plex clients. Not sure where, again still digging - Not sure how no one else is seeing this issue...

@Teagan42
Copy link
Contributor

Even more interesting, realized I don't have the include non clients flag set in my config...

@Teagan42
Copy link
Contributor

@JesseWebDotCom if you got time in about an hour we can hop on a video call and I can show you what I'm seeing.

@JesseWebDotCom
Copy link
Contributor Author

Unfortunately I'm at a family event. Perhaps you can send me a clip. Also, what's your setup (I think I have every plex client in the world - maybe I can reproduce the issue)?

@Teagan42
Copy link
Contributor

Teagan42 commented Mar 16, 2017

I am having issues with my Amazon Fire TVs (haven't even checked the two sticks I have up stairs).

On first pass, the AFTVs are added (as expected), but second pass (the refresh) it seems to duplicate them as non-devices.

When I turn on the INCLUDE_NON_CLIENT config, those (non-client) work just fine, no problems.

@Teagan42
Copy link
Contributor

Teagan42 commented Mar 16, 2017

TV (non-client) works, Chrome (client) works, AFTVs - duplicated... there's something I am missing somewhere...

Scratch that:

TV (Non-Client) Only shows up once ✅
Chrome (Client) Shows up duplicated 🔴
Amazon Fire TV (Client) Shows up duplicated 🔴

Here's an image (I have 2 Amazon Fire TVs - so you'll see both duplicated):

screen shot 2017-03-15 at 6 13 36 pm

@Teagan42
Copy link
Contributor

Fire Sticks have same issue as the TVs

@Teagan42
Copy link
Contributor

Top to bottom:
Amazon Fire TV A (Duplicated - no machine identifier)
Amazon Fire TV B (Duplicated - no machine identifier)
Amazon Fire TV A (Machine Identifier)
Amazon Fire TV B (Machine Identifier)
Android Phone (Machine Identifier)
Chrome (Machine Identifier)
Chrome (Duplicated - no machine identifier)
Amazon Fire Stick A (Machine identifier)
Amazon Fire Stick A (Duplicated - no machine identifier)
Samsung TV A (Non-client, machine identifier)
Samsung TV B (Non-client, machine identifier)

screen shot 2017-03-15 at 6 21 12 pm

@Teagan42
Copy link
Contributor

I have other things to work on tonight - if you can dig in, let me know otherwise I'll try to look tomorrow

@JesseWebDotCom
Copy link
Contributor Author

JesseWebDotCom commented Mar 16, 2017

When you see the duplicate devices, go to http://IP:PORT/status/sessions (ip = plex server) and post the results (make sure it doesn't include any sensitive information). My suspicion is you are either getting blank machine identifiers or duplicate identifiers. If so, that's a big problem as thats the only way to uniquely identify a player (other than a hack like using the client ip).

@JesseWebDotCom
Copy link
Contributor Author

JesseWebDotCom commented Mar 16, 2017

Also, what do you have for a plex server? Are you casting in any of these scenarios? And what is the compared behavior in the existing media_player.plex component?

@balloob balloob dismissed pvizeli’s stale review March 16, 2017 05:03

It looks good

@balloob
Copy link
Member

balloob commented Mar 16, 2017

So the code looks good. This can be merged once the bugs found by @Teagan42 fixed or avoided.

@Teagan42
Copy link
Contributor

Teagan42 commented Mar 16, 2017 via email

@balloob
Copy link
Member

balloob commented Mar 16, 2017

Thanks @JesseWebDotCom for the work and @Teagan42 for testing! 🎉 💃 🐬 🍺

@balloob balloob merged commit 5714f15 into home-assistant:dev Mar 16, 2017
@JesseWebDotCom
Copy link
Contributor Author

Awesome, thanks for teaching

@robbiet480
Copy link
Member

robbiet480 commented Mar 16, 2017

@JesseWebDotCom Thanks for hanging on! We thought that this was such a great pull request and show of effort it was deserving of its own tweet! Cherish it, we don't hand those out lightly 😳

@JesseWebDotCom
Copy link
Contributor Author

JesseWebDotCom commented Mar 16, 2017

Thanks. Hey, I believe I have one more change to make which is a fix to the new show all controls option (it won't work as is). Can I still submit that as a new commit here or is it too late? I just tried to submit and it doesn't look like it worked:
https://github.com/JesseWebDotCom/home-assistant/commit/3bb8fc080d47904b2f8da4f299532b86c91066e1

Also, how can I tell if my associated documentation pull request is approved and ready to be released at the same time as this component?

@balloob balloob mentioned this pull request Mar 24, 2017
@home-assistant home-assistant locked and limited conversation to collaborators Jul 17, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.