From 650a88d6388a8a53e6c6bfdc48295b0626333e21 Mon Sep 17 00:00:00 2001 From: Michael Shepanski Date: Fri, 12 May 2017 23:25:57 -0400 Subject: [PATCH] Started movinf client tests into Pytest framework --- plexapi/client.py | 13 +++++++--- plexapi/media.py | 9 +++---- plexapi/video.py | 10 +++++++- tests/conftest.py | 4 ++-- tests/test_client.py | 57 +++++++++++++++++++++++++++++++++++--------- tests/test_server.py | 4 ++-- tests/test_video.py | 5 ++-- 7 files changed, 75 insertions(+), 27 deletions(-) diff --git a/plexapi/client.py b/plexapi/client.py index 37fe811d..7b6ef6ea 100644 --- a/plexapi/client.py +++ b/plexapi/client.py @@ -70,6 +70,10 @@ class PlexClient(PlexObject): if connect and self._baseurl: self.connect(timeout=timeout) + def _nextCommandId(self): + self._commandId += 0 + return self._commandId + def connect(self, timeout=None): """ Alias of reload as any subsequent requests to this client will be made directly to the device even if the object attributes were initially @@ -113,7 +117,7 @@ class PlexClient(PlexObject): headers.update(kwargs) return headers - def proxyThroughServer(self, value=True): + def proxyThroughServer(self, value=True, server=None): """ Tells this PlexClient instance to proxy all future commands through the PlexServer. Useful if you do not wish to connect directly to the Client device itself. @@ -123,6 +127,8 @@ class PlexClient(PlexObject): Raises: :class:`~plexapi.exceptions.Unsupported`: Cannot use client proxy with unknown server. """ + if server: + self._server = server if value is True and not self._server: raise Unsupported('Cannot use client proxy with unknown server.') self._proxyThroughServer = value @@ -165,8 +171,7 @@ class PlexClient(PlexObject): raise Unsupported('Client %s doesnt support %s controller.' % (self.title, controller)) key = '/player/%s%s' % (command, utils.joinArgs(params)) headers = {'X-Plex-Target-Client-Identifier': self.machineIdentifier} - self._commandId += 1 - params['commandID'] = self._commandId + params['commandID'] = self._nextCommandId() proxy = self._proxyThroughServer if proxy is None else proxy if proxy: return self._server.query(key, headers=headers) @@ -428,6 +433,8 @@ class PlexClient(PlexObject): 'port': server_url[-1], 'offset': offset, 'key': media.key, + 'token': self._server._token, + 'commandID': self._nextCommandId(), 'containerKey': '/playQueues/%s?window=100&own=1' % playqueue.playQueueID, }, **params)) diff --git a/plexapi/media.py b/plexapi/media.py index 7d28ab8c..122f9533 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -93,20 +93,17 @@ class MediaPart(PlexObject): streams.append(cls(self._server, elem, self._initpath)) return streams - @property def videoStreams(self): """ Returns a list of :class:`~plexapi.media.VideoStream` objects in this MediaPart. """ - return [s for s in self.streams if s.streamType == VideoStream.STREAMTYPE] + return [stream for stream in self.streams if stream.streamType == VideoStream.STREAMTYPE] - @property def audioStreams(self): """ Returns a list of :class:`~plexapi.media.AudioStream` objects in this MediaPart. """ - return [s for s in self.streams if s.streamType == AudioStream.STREAMTYPE] + return [stream for stream in self.streams if stream.streamType == AudioStream.STREAMTYPE] - @property def subtitleStreams(self): """ Returns a list of :class:`~plexapi.media.SubtitleStream` objects in this MediaPart. """ - return [s for s in self.streams if s.streamType == SubtitleStream.STREAMTYPE] + return [stream for stream in self.streams if stream.streamType == SubtitleStream.STREAMTYPE] class MediaPartStream(PlexObject): diff --git a/plexapi/video.py b/plexapi/video.py index b172be35..ccda1530 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -144,7 +144,15 @@ class Movie(Video, Playable): """ This does not exist in plex xml response but is added to have a common interface to get the location of the Movie/Show/Episode """ - return [p.file for p in self.iterParts() if p] + return [part.file for part in self.iterParts() if part] + + def subtitleStreams(self): + """ Returns a list of :class:`~plexapi.media.SubtitleStream` objects for all MediaParts. """ + streams = [] + for elem in self.media: + for part in elem.parts: + streams += part.subtitleStreams() + return streams def _prettyfilename(self): # This is just for compat. diff --git a/tests/conftest.py b/tests/conftest.py index a2178cc4..965d89b2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,7 +30,7 @@ MYPLEX_PASSWORD = plexapi.CONFIG.get('auth.myplex_password') CLIENT_BASEURL = plexapi.CONFIG.get('auth.client_baseurl') CLIENT_TOKEN = plexapi.CONFIG.get('auth.client_token') -MIN_DATETIME = datetime(2008, 1, 1) +MIN_DATETIME = datetime(1999, 1, 1) REGEX_EMAIL = r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)' REGEX_IPADDR = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' @@ -79,7 +79,7 @@ def plex2(): @pytest.fixture() def client(request): - return PlexClient(baseurl=CLIENT_BASEURL, token=CLIENT_TOKEN) + return PlexClient(plex(), baseurl=CLIENT_BASEURL, token=CLIENT_TOKEN) @pytest.fixture() diff --git a/tests/test_client.py b/tests/test_client.py index 4b5129fa..cc83f1a2 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -2,6 +2,18 @@ import pytest, time +def _check_capabilities(client, capabilities): + supported = client.protocolCapabilities + for capability in capabilities: + if capability not in supported: + pytest.skip('Client doesnt support %s capability.', capability) + + +def _check_proxy(plex, client, proxy): + if proxy: + client.proxyThroughServer(server=plex) + + @pytest.mark.client def test_list_clients(account, plex): assert account.resources(), 'MyPlex is not listing any devlices.' @@ -10,17 +22,10 @@ def test_list_clients(account, plex): @pytest.mark.client -def test_client_navigation_direct(plex, client, episode, artist): - _navigate(plex, client, episode, artist) - - -@pytest.mark.client -def test_client_navigation_via_proxy(plex, client, episode, artist): - client.proxyThroughServer() - _navigate(plex, client, episode, artist) - - -def _navigate(plex, client, episode, artist): +@pytest.mark.parametrize('proxy', [False, True]) +def test_client_navigation(plex, client, episode, artist, proxy): + _check_capabilities(client, ['navigation']) + _check_proxy(plex, client, proxy) # Browse around a bit.. client.moveDown(); time.sleep(0.5) client.moveDown(); time.sleep(0.5) @@ -44,6 +49,36 @@ def _navigate(plex, client, episode, artist): client.goBack(); time.sleep(5) +@pytest.mark.client +@pytest.mark.parametrize('proxy', [False, True]) +def test_video_playback(plex, client, movie, proxy): + _check_capabilities(client, ['playback']) + _check_proxy(plex, client, proxy) + try: + # Need a movie with subtitles + movie = plex.library.section('Movies').get('Moana').reload() + mtype = 'video' + subs = [stream for stream in movie.subtitleStreams() if stream.language == 'English'] + # Basic play ability + print('Basic play ability') + client.playMedia(movie); time.sleep(5) + client.pause(mtype); time.sleep(2) + # Step forward, back, seek in time + print('Step forward, back, seek in time') + client.stepForward(mtype); time.sleep(5) + client.play(mtype); time.sleep(3) + client.stepBack(mtype); time.sleep(5) + client.play(mtype); time.sleep(3) + client.seekTo(10*60*1000); time.sleep(5) + # Enable subtitles + print('Enable subtitles') + client.setSubtitleStream(0, mtype); time.sleep(10) + client.setSubtitleStream(subs[0].id, mtype); time.sleep(10) + client.stop(mtype); time.sleep(1) + finally: + movie.markWatched() + + @pytest.mark.client def _test_client_PlexClient__loadData(pms): pass diff --git a/tests/test_server.py b/tests/test_server.py index 3939005b..da9930cb 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -20,7 +20,7 @@ def test_server_attr(plex): assert plex.platform in ('Linux', 'Windows') assert len(plex.platformVersion) >= 5 assert plex._token == utils.SERVER_TOKEN - assert plex.transcoderActiveVideoSessions == 0 + assert utils.is_int(plex.transcoderActiveVideoSessions, gte=0) assert utils.is_datetime(plex.updatedAt) assert len(plex.version) >= 5 @@ -168,7 +168,7 @@ def test_server_client_not_found(plex): def test_server_Server_sessions(plex): - assert len(plex.sessions()) == 0 + assert len(plex.sessions()) >= 0 @pytest.mark.client diff --git a/tests/test_video.py b/tests/test_video.py index 2f635f7b..4d135176 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -81,7 +81,8 @@ def test_video_Movie_attrs(movies): assert movie.originallyAvailableAt.strftime('%Y-%m-%d') in ('2008-01-11', '2008-02-11') assert movie.player is None assert movie.playlistItemID is None - assert movie.primaryExtraKey is None + if movie.primaryExtraKey: + assert utils.is_metadata(movie.primaryExtraKey) assert [i.tag for i in movie.producers] == [] assert float(movie.rating) >= 6.4 assert movie.ratingImage == 'rottentomatoes://image.rating.ripe' @@ -460,7 +461,7 @@ def test_video_Episode_attrs(episode): def test_video_Season(show): seasons = show.seasons() assert len(seasons) >= 1 - assert ['Season 1', 'Season 2'] == [s.title for s in seasons] + assert ['Season 1', 'Season 2'] == [s.title for s in seasons[:2]] assert show.season('Season 1') == seasons[0]