From b938b471220b2ca4884421394c411198ba0abcf7 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:50:39 -0700 Subject: [PATCH 1/9] Add switchHomeUser method to PlexServer --- plexapi/myplex.py | 19 ++++++++++++++----- plexapi/playlist.py | 6 +++--- plexapi/server.py | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/plexapi/myplex.py b/plexapi/myplex.py index 58c135a98..0689d206d 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -497,13 +497,18 @@ def removeHomeUser(self, user): url = self.HOMEUSER.format(userId=user.id) return self.query(url, self._session.delete) - def switchHomeUser(self, user, pin=None): - """ Returns a new :class:`~plexapi.myplex.MyPlexAccount` object switched to the given home user. + def switchHomeUser(self, user, pin=None, session=None, timeout=None): + """ Returns a new :class:`~plexapi.myplex.MyPlexAccount` object switched to the given Plex Home user. Parameters: user (:class:`~plexapi.myplex.MyPlexUser` or str): :class:`~plexapi.myplex.MyPlexUser`, - username, or email of the home user to switch to. - pin (str): PIN for the home user (required if the home user has a PIN set). + username, or email of the Plex Home user to switch to. + pin (str): PIN for the Plex Home user (required if the Plex Home user has a PIN set). + session (requests.Session, optional): Use your own session object if you want to + cache the http responses from the server. This will default to the same + session as the current account if no new session is provided. + timeout (int, optional): Timeout in seconds on initial connection to the server. + This will default to the same timeout as the current account if no new timeout is provided. Example: @@ -523,7 +528,11 @@ def switchHomeUser(self, user, pin=None): params['pin'] = pin data = self.query(url, self._session.post, params=params) userToken = data.attrib.get('authenticationToken') - return MyPlexAccount(token=userToken, session=self._session) + if session is None: + session = self._session + if timeout is None: + timeout = self._timeout + return MyPlexAccount(token=userToken, session=session, timeout=timeout) def setPin(self, newPin, currentPin=None): """ Set a new Plex Home PIN for the account. diff --git a/plexapi/playlist.py b/plexapi/playlist.py index 80dcb2dd7..d78a35c37 100644 --- a/plexapi/playlist.py +++ b/plexapi/playlist.py @@ -443,13 +443,13 @@ def create(cls, server, title, section=None, items=None, smart=False, limit=None return cls._create(server, title, items) def copyToUser(self, user): - """ Copy playlist to another user account. + """ Copy playlist to another Plex Home user account. Parameters: user (:class:`~plexapi.myplex.MyPlexUser` or str): `MyPlexUser` object, username, - email, or user id of the user to copy the playlist to. + email, or user id of the Plex Home user to copy the playlist to. """ - userServer = self._server.switchUser(user) + userServer = self._server.switchHomeUser(user) return self.create(server=userServer, title=self.title, items=self.items()) def sync(self, videoQuality=None, photoResolution=None, audioBitrate=None, client=None, clientId=None, limit=None, diff --git a/plexapi/server.py b/plexapi/server.py index 7f930562c..f9082263a 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -234,8 +234,10 @@ def createToken(self, type='delegation', scope='all'): q = self.query(f'/security/token?type={type}&scope={scope}') return q.attrib.get('token') + @utils.deprecated('switchUser is deprecated, use switchHomeUser instead') def switchUser(self, user, session=None, timeout=None): - """ Returns a new :class:`~plexapi.server.PlexServer` object logged in as the given username. + """ Deprecated. Use :meth:`~plexapi.server.PlexServer.switchHomeUser` instead. + Returns a new :class:`~plexapi.server.PlexServer` object logged in as the given username. Note: Only the admin account can switch to other users. Parameters: @@ -258,14 +260,38 @@ def switchUser(self, user, session=None, timeout=None): # Login to the same Plex server using a different account userPlex = plex.switchUser("Username") + """ + return self.switchHomeUser(user, session=session, timeout=timeout) + + def switchHomeUser(self, user, pin=None, session=None, timeout=None): + """ Returns a new :class:`~plexapi.server.PlexServer` object logged in as the given Plex Home user. + Note: Only the admin account can switch to other users. + + Parameters: + user (:class:`~plexapi.myplex.MyPlexUser` or str): :class:`~plexapi.myplex.MyPlexUser`, + username, or email of the Plex Home user to switch to. + pin (str): PIN for the Plex Home user (required if the Plex Home user has a PIN set). + session (requests.Session, optional): Use your own session object if you want to + cache the http responses from the server. This will default to the same + session as the current account if no new session is provided. + timeout (int, optional): Timeout in seconds on initial connection to the server. + This will default to the same timeout as the current account if no new timeout is provided. + + Example: + + .. code-block:: python + + from plexapi.server import PlexServer + # Login to the Plex server using the admin token + plex = PlexServer('http://plexserver:32400', token='2ffLuB84dqLswk9skLos') + # Login to the same Plex server using a different Plex Home user account + userPlex = plex.switchHomeUser("Username") + """ from plexapi.myplex import MyPlexUser user = user if isinstance(user, MyPlexUser) else self.myPlexAccount().user(user) - userToken = user.get_token(self.machineIdentifier) - if session is None: - session = self._session - if timeout is None: - timeout = self._timeout + userAccount = self.myPlexAccount().switchHomeUser(user, pin=pin, session=session, timeout=timeout) + userToken = userAccount.resource(self.machineIdentifier).accessToken return PlexServer(self._baseurl, token=userToken, session=session, timeout=timeout) @cached_data_property From 655328c47d4429d08ddbd46c6f6f3ffa587e51c0 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:11:08 -0700 Subject: [PATCH 2/9] Fix default session and timeout in switchHomeUser --- plexapi/server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plexapi/server.py b/plexapi/server.py index f9082263a..0ed37baf9 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -290,6 +290,10 @@ def switchHomeUser(self, user, pin=None, session=None, timeout=None): """ from plexapi.myplex import MyPlexUser user = user if isinstance(user, MyPlexUser) else self.myPlexAccount().user(user) + if session is None: + session = self._session + if timeout is None: + timeout = self._timeout userAccount = self.myPlexAccount().switchHomeUser(user, pin=pin, session=session, timeout=timeout) userToken = userAccount.resource(self.machineIdentifier).accessToken return PlexServer(self._baseurl, token=userToken, session=session, timeout=timeout) From 6ddae6efbd4f9c0fc29db9f428efa67c102ebd08 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:12:08 -0700 Subject: [PATCH 3/9] Remove switchUser example --- plexapi/server.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/plexapi/server.py b/plexapi/server.py index 0ed37baf9..03b7b72e8 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -249,17 +249,6 @@ def switchUser(self, user, session=None, timeout=None): timeout (int, optional): Timeout in seconds on initial connection to the server. This will default to the same timeout as the admin account if no new timeout is provided. - - Example: - - .. code-block:: python - - from plexapi.server import PlexServer - # Login to the Plex server using the admin token - plex = PlexServer('http://plexserver:32400', token='2ffLuB84dqLswk9skLos') - # Login to the same Plex server using a different account - userPlex = plex.switchUser("Username") - """ return self.switchHomeUser(user, session=session, timeout=timeout) From c4834ffe91c0c9c27e94178c4606537e77a2b06d Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:14:46 -0700 Subject: [PATCH 4/9] Remove user id from Playlist copyToUser docstring --- plexapi/playlist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plexapi/playlist.py b/plexapi/playlist.py index d78a35c37..6817514e5 100644 --- a/plexapi/playlist.py +++ b/plexapi/playlist.py @@ -447,7 +447,7 @@ def copyToUser(self, user): Parameters: user (:class:`~plexapi.myplex.MyPlexUser` or str): `MyPlexUser` object, username, - email, or user id of the Plex Home user to copy the playlist to. + or email of the Plex Home user to copy the playlist to. """ userServer = self._server.switchHomeUser(user) return self.create(server=userServer, title=self.title, items=self.items()) From 27d753109c4f96e6ce47db26c5668a92359bebca Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:18:52 -0700 Subject: [PATCH 5/9] Update Playlist copyToUser test --- tests/test_playlist.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_playlist.py b/tests/test_playlist.py index 7c2b1be5a..a60cd2ff5 100644 --- a/tests/test_playlist.py +++ b/tests/test_playlist.py @@ -149,13 +149,12 @@ def test_Play_photos(plex, client, photoalbum): time.sleep(2) -def test_Playlist_copyToUser(plex, show, fresh_plex, shared_username): +def test_Playlist_copyToUser(plex, show, shared_username): episodes = show.episodes() playlist = plex.createPlaylist('shared_from_test_plexapi', items=episodes) try: playlist.copyToUser(shared_username) - user = plex.myPlexAccount().user(shared_username) - user_plex = fresh_plex(plex._baseurl, user.get_token(plex.machineIdentifier)) + user_plex = plex.switchHomeUser(shared_username) assert playlist.title in [p.title for p in user_plex.playlists()] finally: playlist.delete() From ad42ae311476d37adfdfdcb3b92f7b9ec370f37c Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:33:01 -0700 Subject: [PATCH 6/9] Ensure session and timeout are used for home user switching --- plexapi/myplex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plexapi/myplex.py b/plexapi/myplex.py index 0689d206d..f324c1453 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -526,12 +526,12 @@ def switchHomeUser(self, user, pin=None, session=None, timeout=None): params = {} if pin: params['pin'] = pin - data = self.query(url, self._session.post, params=params) - userToken = data.attrib.get('authenticationToken') if session is None: session = self._session if timeout is None: timeout = self._timeout + data = self.query(url, session.post, params=params, timeout=timeout) + userToken = data.attrib.get('authenticationToken') return MyPlexAccount(token=userToken, session=session, timeout=timeout) def setPin(self, newPin, currentPin=None): From b8e94252eab2054aa83e48a2779aa0c89e4b5b08 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:33:18 -0700 Subject: [PATCH 7/9] Assert user is a home user in Playlist copyToUser test --- tests/test_playlist.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_playlist.py b/tests/test_playlist.py index a60cd2ff5..9f1997606 100644 --- a/tests/test_playlist.py +++ b/tests/test_playlist.py @@ -154,7 +154,9 @@ def test_Playlist_copyToUser(plex, show, shared_username): playlist = plex.createPlaylist('shared_from_test_plexapi', items=episodes) try: playlist.copyToUser(shared_username) - user_plex = plex.switchHomeUser(shared_username) + user = plex.myPlexAccount().user(shared_username) + assert user.home is True + user_plex = plex.switchHomeUser(user) assert playlist.title in [p.title for p in user_plex.playlists()] finally: playlist.delete() From a5ed12db9c9145348aba9bd29669b3f043122407 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:43:16 -0700 Subject: [PATCH 8/9] Remove home users don't have email comment --- plexapi/myplex.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plexapi/myplex.py b/plexapi/myplex.py index f324c1453..0c501508b 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -689,7 +689,6 @@ def user(self, username): """ username = str(username) for user in self.users(): - # Home users don't have email, username etc. if username.lower() == user.title.lower(): return user From 66cd93eefea6056aaa954d6d4d34b03924d2ccbc Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:43:42 -0700 Subject: [PATCH 9/9] Add pin parameter to Playlist copyToUser --- plexapi/playlist.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plexapi/playlist.py b/plexapi/playlist.py index 6817514e5..ab905c612 100644 --- a/plexapi/playlist.py +++ b/plexapi/playlist.py @@ -442,14 +442,15 @@ def create(cls, server, title, section=None, items=None, smart=False, limit=None else: return cls._create(server, title, items) - def copyToUser(self, user): + def copyToUser(self, user, pin=None): """ Copy playlist to another Plex Home user account. Parameters: user (:class:`~plexapi.myplex.MyPlexUser` or str): `MyPlexUser` object, username, or email of the Plex Home user to copy the playlist to. + pin (str): PIN for the Plex Home user (required if the Plex Home user has a PIN set). """ - userServer = self._server.switchHomeUser(user) + userServer = self._server.switchHomeUser(user, pin=pin) return self.create(server=userServer, title=self.title, items=self.items()) def sync(self, videoQuality=None, photoResolution=None, audioBitrate=None, client=None, clientId=None, limit=None,