24 Commits

Author SHA1 Message Date
Luigi311
a4365e59f3 Merge pull request #44 from luigi311/dev
Fix issues with certain libraries failing
2023-02-26 13:32:26 -07:00
Luigi311
b960bccb86 Plex: Fix guids error on mark 2023-02-25 18:42:07 -07:00
Luigi311
218037200c Jellyfin: Fix tv show searching for watched 2023-02-25 18:27:01 -07:00
Luigi311
4ac670e837 Plex: Do not error if guids can not be gathered. Parallelize show processing for get watched. 2023-02-25 16:58:57 -07:00
Luigi311
96eff65c3e Do not error if failed to get library watched 2023-02-25 15:03:27 -07:00
Luigi311
45471607c8 Merge pull request #43 from JChris246/chore/spelling
Correct some spelling issues
2023-02-22 09:51:42 -07:00
JChris246
14885744b1 fix: correct some spelling issues 2023-02-22 00:09:30 -04:00
Luigi311
d1fd61f1d1 Merge pull request #38 from luigi311/dev
Fix issue with nested folders
2023-01-31 16:27:54 -07:00
Luigi311
6c1ee4a7dc Log server users 2023-01-30 11:56:27 -07:00
Luigi311
9a8e799e68 Recursive all the things. Use includeItemType 2023-01-30 11:46:12 -07:00
Luigi311
ffec4e2f28 Support multiple library types 2023-01-28 16:33:36 -07:00
Luigi311
00102891a5 Catch None for types 2023-01-27 23:45:03 -07:00
Luigi311
aa76b83428 Use isinstance instead of type 2023-01-27 12:21:38 -07:00
Luigi311
a644189ea5 Use isinstance instead of type 2023-01-27 12:18:15 -07:00
Luigi311
c5d987a8c9 Update .env.sample and README 2023-01-27 11:23:58 -07:00
Luigi311
bdd68ad68d If user is type str get plex object 2023-01-27 11:02:15 -07:00
Luigi311
2d86bca781 Update github actions 2023-01-27 10:48:52 -07:00
Luigi311
1b01ff6ec2 Log if multiple types and continue instead of error 2023-01-27 10:45:46 -07:00
Luigi311
f08ec43507 Skip library before erroring for multiple types. 2023-01-27 10:43:50 -07:00
Luigi311
7f9424260a Format 2023-01-26 14:03:13 -07:00
Luigi311
5f21943353 Exclude folders, use recursive. 2023-01-26 13:55:50 -07:00
Luigi311
a5a795f43c Exclude Folders from list 2023-01-26 13:42:35 -07:00
Luigi311
fcb6d7625f Fix invalid library types, raise mixed types 2023-01-26 13:31:57 -07:00
Luigi311
fd2179998f Fix ssl_bypass for plex 2023-01-26 11:23:47 -07:00
8 changed files with 303 additions and 124 deletions

View File

@@ -1,43 +1,68 @@
# Global Settings
## Do not mark any shows/movies as played and instead just output to log if they would of been marked.
DRYRUN = "True"
## Additional logging information
DEBUG = "True"
DEBUG = "False"
## Debugging level, "info" is default, "debug" is more verbose
DEBUG_LEVEL = "info"
## How often to run the script in seconds
SLEEP_DURATION = "3600"
## Log file where all output will be written to
LOGFILE = "log.log"
## Map usernames between plex and jellyfin in the event that they are different, order does not matter
#USER_MAPPING = { "testuser2": "testuser3" }
## Map libraries between plex and jellyfin in the even that they are different, order does not matter
#LIBRARY_MAPPING = { "Shows": "TV Shows" }
## Map usernames between servers in the event that they are different, order does not matter
## Comma separated for multiple options
#USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" }
## Recommended to use token as it is faster to connect as it is direct to the server instead of going through the plex servers
## URL of the plex server, use hostname or IP address if the hostname is not resolving correctly
## Comma seperated list for multiple servers
PLEX_BASEURL = "http://localhost:32400"
## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/
PLEX_TOKEN = "SuperSecretToken"
## If not using plex token then use username and password of the server admin along with the servername
#PLEX_USERNAME = ""
#PLEX_PASSWORD = ""
#PLEX_SERVERNAME = "Plex Server"
## Skip hostname validation for ssl certificates.
SSL_BYPASS = "False"
## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly
## Comma seperated list for multiple servers
JELLYFIN_BASEURL = "http://localhost:8096"
## Jellyfin api token, created manually by logging in to the jellyfin server admin dashboard and creating an api key
JELLYFIN_TOKEN = "SuperSecretToken"
## Map libraries between servers in the even that they are different, order does not matter
## Comma separated for multiple options
#LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" }
## Blacklisting/Whitelisting libraries, library types such as Movies/TV Shows, and users. Mappings apply so if the mapping for the user or library exist then both will be excluded.
## Comma separated for multiple options
#BLACKLIST_LIBRARY = ""
#WHITELIST_LIBRARY = ""
#BLACKLIST_LIBRARY_TYPE = ""
#WHITELIST_LIBRARY_TYPE = ""
#BLACKLIST_USERS = ""
WHITELIST_USERS = "testuser1,testuser2"
# Plex
## Recommended to use token as it is faster to connect as it is direct to the server instead of going through the plex servers
## URL of the plex server, use hostname or IP address if the hostname is not resolving correctly
## Comma separated list for multiple servers
PLEX_BASEURL = "http://localhost:32400, https://nas:32400"
## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/
## Comma separated list for multiple servers
PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2"
## If not using plex token then use username and password of the server admin along with the servername
## Comma separated for multiple options
#PLEX_USERNAME = "PlexUser, PlexUser2"
#PLEX_PASSWORD = "SuperSecret, SuperSecret2"
#PLEX_SERVERNAME = "Plex Server1, Plex Server2"
## Skip hostname validation for ssl certificates.
## Set to True if running into ssl certificate errors
SSL_BYPASS = "False"
# Jellyfin
## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly
## Comma separated list for multiple servers
JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096"
## Jellyfin api token, created manually by logging in to the jellyfin server admin dashboard and creating an api key
## Comma separated list for multiple servers
JELLYFIN_TOKEN = "SuperSecretToken, SuperSecretToken2"

View File

@@ -13,7 +13,7 @@ jobs:
pytest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install dependencies"
run: pip install -r requirements.txt && pip install -r test/requirements.txt
@@ -26,7 +26,7 @@ jobs:
needs: pytest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Docker meta
id: docker_meta
@@ -45,14 +45,14 @@ jobs:
type=sha
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
if: "${{ steps.docker_meta.outcome == 'success' }}"
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
@@ -60,7 +60,7 @@ jobs:
- name: Build
id: build
if: "${{ steps.docker_meta.outcome == 'skipped' }}"
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile
@@ -71,7 +71,7 @@ jobs:
- name: Build Push
id: build_push
if: "${{ steps.docker_meta.outcome == 'success' }}"
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}

View File

@@ -2,14 +2,84 @@
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/26b47c5db63942f28f02f207f692dc85)](https://www.codacy.com/gh/luigi311/JellyPlex-Watched/dashboard?utm_source=github.com&utm_medium=referral&utm_content=luigi311/JellyPlex-Watched&utm_campaign=Badge_Grade)
Sync watched between jellyfin and plex
Sync watched between jellyfin and plex locally
## Description
Keep in sync all your users watched history between jellyfin and plex servers locally. This uses the imdb ids and any other matching id to find the correct episode/movie between the two. This is not perfect but it works for most cases. You can use this for as many servers as you want by enterying multiple options in the .env plex/jellyfin section seperated by commas.
Keep in sync all your users watched history between jellyfin and plex servers locally. This uses file names and provider ids to find the correct episode/movie between the two. This is not perfect but it works for most cases. You can use this for as many servers as you want by entering multiple options in the .env plex/jellyfin section separated by commas.
## Configuration
```bash
# Global Settings
## Do not mark any shows/movies as played and instead just output to log if they would of been marked.
DRYRUN = "True"
## Additional logging information
DEBUG = "False"
## Debugging level, "info" is default, "debug" is more verbose
DEBUG_LEVEL = "info"
## How often to run the script in seconds
SLEEP_DURATION = "3600"
## Log file where all output will be written to
LOGFILE = "log.log"
## Map usernames between servers in the event that they are different, order does not matter
## Comma separated for multiple options
USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" }
## Map libraries between servers in the even that they are different, order does not matter
## Comma separated for multiple options
LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" }
## Blacklisting/Whitelisting libraries, library types such as Movies/TV Shows, and users. Mappings apply so if the mapping for the user or library exist then both will be excluded.
## Comma separated for multiple options
BLACKLIST_LIBRARY = ""
WHITELIST_LIBRARY = ""
BLACKLIST_LIBRARY_TYPE = ""
WHITELIST_LIBRARY_TYPE = ""
BLACKLIST_USERS = ""
WHITELIST_USERS = "testuser1,testuser2"
# Plex
## Recommended to use token as it is faster to connect as it is direct to the server instead of going through the plex servers
## URL of the plex server, use hostname or IP address if the hostname is not resolving correctly
## Comma separated list for multiple servers
PLEX_BASEURL = "http://localhost:32400, https://nas:32400"
## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/
## Comma separated list for multiple servers
PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2"
## If not using plex token then use username and password of the server admin along with the servername
## Comma separated for multiple options
#PLEX_USERNAME = "PlexUser, PlexUser2"
#PLEX_PASSWORD = "SuperSecret, SuperSecret2"
#PLEX_SERVERNAME = "Plex Server1, Plex Server2"
## Skip hostname validation for ssl certificates.
## Set to True if running into ssl certificate errors
SSL_BYPASS = "False"
# Jellyfin
## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly
## Comma separated list for multiple servers
JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096"
## Jellyfin api token, created manually by logging in to the jellyfin server admin dashboard and creating an api key
## Comma separated list for multiple servers
JELLYFIN_TOKEN = "SuperSecretToken, SuperSecretToken2"
```
## Installation
@@ -66,7 +136,7 @@ Keep in sync all your users watched history between jellyfin and plex servers lo
## Contributing
I am open to recieving pull requests. If you are submitting a pull request, please make sure run it locally for a day or two to make sure it is working as expected and stable. Make all pull requests against the dev branch and nothing will be merged into the main without going through the lower branches.
I am open to receiving pull requests. If you are submitting a pull request, please make sure run it locally for a day or two to make sure it is working as expected and stable. Make all pull requests against the dev branch and nothing will be merged into the main without going through the lower branches.
## License

View File

@@ -168,8 +168,13 @@ def check_skip_logic(
):
skip_reason = None
if library_type.lower() in blacklist_library_type:
skip_reason = "is blacklist_library_type"
if isinstance(library_type, (list, tuple, set)):
for library_type_item in library_type:
if library_type_item.lower() in blacklist_library_type:
skip_reason = "is blacklist_library_type"
else:
if library_type.lower() in blacklist_library_type:
skip_reason = "is blacklist_library_type"
if library_title.lower() in [x.lower() for x in blacklist_library]:
skip_reason = "is blacklist_library"
@@ -182,8 +187,13 @@ def check_skip_logic(
skip_reason = "is blacklist_library"
if len(whitelist_library_type) > 0:
if library_type.lower() not in whitelist_library_type:
skip_reason = "is not whitelist_library_type"
if isinstance(library_type, (list, tuple, set)):
for library_type_item in library_type:
if library_type_item.lower() not in whitelist_library_type:
skip_reason = "is not whitelist_library_type"
else:
if library_type.lower() not in whitelist_library_type:
skip_reason = "is not whitelist_library_type"
# if whitelist is not empty and library is not in whitelist
if len(whitelist_library) > 0:

View File

@@ -1,4 +1,4 @@
import asyncio, aiohttp
import asyncio, aiohttp, traceback
from src.functions import (
logger,
search_mapping,
@@ -46,9 +46,14 @@ class Jellyfin:
) as response:
results = await response.json()
if type(results) is str:
logger(f"Jellyfin: Query {query_type} {query} {results}", 2)
raise Exception(results)
# append identifiers to results
if identifiers:
results["Identifiers"] = identifiers
return results
except Exception as e:
@@ -63,7 +68,7 @@ class Jellyfin:
async with aiohttp.ClientSession() as session:
response = await self.query(query_string, "get", session)
# If reponse is not empty
# If response is not empty
if response:
for user in response:
users[user["Name"]] = user["Id"]
@@ -92,7 +97,7 @@ class Jellyfin:
user_watched[user_name][library_title] = []
watched = await self.query(
f"/Users/{user_id}/Items"
+ f"?ParentId={library_id}&Filters=IsPlayed&Fields=ItemCounts,ProviderIds,MediaSources",
+ f"?ParentId={library_id}&Filters=IsPlayed&IncludeItemTypes=Movie&Recursive=True&Fields=ItemCounts,ProviderIds,MediaSources",
"get",
session,
)
@@ -148,14 +153,14 @@ class Jellyfin:
)
# TV Shows
if library_type == "Series":
if library_type in ["Series", "Episode"]:
# Initialize an empty dictionary for the given user and library
user_watched[user_name][library_title] = {}
# Retrieve a list of watched TV shows
watched_shows = await self.query(
f"/Users/{user_id}/Items"
+ f"?ParentId={library_id}&isPlaceHolder=false&Fields=ProviderIds,Path,RecursiveItemCount",
+ f"?ParentId={library_id}&isPlaceHolder=false&IncludeItemTypes=Series&Recursive=True&Fields=ProviderIds,Path,RecursiveItemCount",
"get",
session,
)
@@ -184,6 +189,7 @@ class Jellyfin:
"show_guids": show_guids,
"show_id": show["Id"],
}
season_task = asyncio.ensure_future(
self.query(
f"/Shows/{show['Id']}/Seasons"
@@ -309,7 +315,9 @@ class Jellyfin:
f"Jellyfin: Failed to get watched for {user_name} in library {library_title}, Error: {e}",
2,
)
raise Exception(e)
logger(traceback.format_exc(), 2)
return {}
async def get_users_watched(
self,
@@ -339,7 +347,7 @@ class Jellyfin:
task = asyncio.ensure_future(
self.query(
f"/Users/{user_id}/Items"
+ f"?ParentId={library_id}&Filters=IsPlayed&limit=1",
+ f"?ParentId={library_id}&Filters=IsPlayed&Recursive=True&excludeItemTypes=Folder&limit=100",
"get",
session,
identifiers=identifiers,
@@ -357,11 +365,18 @@ class Jellyfin:
library_id = watched["Identifiers"]["library_id"]
library_title = watched["Identifiers"]["library_title"]
library_type = watched["Items"][0]["Type"]
# Get all library types excluding "Folder"
types = set(
[
x["Type"]
for x in watched["Items"]
if x["Type"] in ["Movie", "Series", "Episode"]
]
)
skip_reason = check_skip_logic(
library_title,
library_type,
types,
blacklist_library,
whitelist_library,
blacklist_library_type,
@@ -376,15 +391,35 @@ class Jellyfin:
)
continue
# Get watched for user
task = asyncio.ensure_future(
self.get_user_library_watched(
user_name, user_id, library_type, library_id, library_title
# If there are multiple types in library raise error
if types is None or len(types) < 1:
all_types = set(
[
x["Type"]
for x in watched["Items"]
]
)
)
tasks_watched.append(task)
logger(
f"Jellyfin: Skipping Library {library_title} found types: {types}, all types: {all_types}",
1,
)
continue
for library_type in types:
# Get watched for user
task = asyncio.ensure_future(
self.get_user_library_watched(
user_name,
user_id,
library_type,
library_id,
library_title,
)
)
tasks_watched.append(task)
watched = await asyncio.gather(*tasks_watched, return_exceptions=True)
return watched
except Exception as e:
logger(f"Jellyfin: Failed to get users watched, Error: {e}", 2)
@@ -450,8 +485,8 @@ class Jellyfin:
if videos_movies_ids:
jellyfin_search = await self.query(
f"/Users/{user_id}/Items"
+ f"?SortBy=SortName&SortOrder=Ascending&Recursive=false&ParentId={library_id}"
+ "&isPlayed=false&Fields=ItemCounts,ProviderIds,MediaSources",
+ f"?SortBy=SortName&SortOrder=Ascending&Recursive=True&ParentId={library_id}"
+ "&isPlayed=false&Fields=ItemCounts,ProviderIds,MediaSources&IncludeItemTypes=Movie",
"get",
session,
)
@@ -504,8 +539,8 @@ class Jellyfin:
if videos_shows_ids and videos_episodes_ids:
jellyfin_search = await self.query(
f"/Users/{user_id}/Items"
+ f"?SortBy=SortName&SortOrder=Ascending&Recursive=false&ParentId={library_id}"
+ "&isPlayed=false&Fields=ItemCounts,ProviderIds,Path",
+ f"?SortBy=SortName&SortOrder=Ascending&Recursive=True&ParentId={library_id}"
+ "&isPlayed=false&Fields=ItemCounts,ProviderIds,Path&IncludeItemTypes=Series",
"get",
session,
)

View File

@@ -113,12 +113,12 @@ def setup_users(
if len(output_server_1_users) == 0:
raise Exception(
f"No users found for server 1, users found {users} filtered users {users_filtered}"
f"No users found for server 1 {server_1_type}, users found {users}, filtered users {users_filtered}, server 1 users {server_1_connection.users}"
)
if len(output_server_2_users) == 0:
raise Exception(
f"No users found for server 2, users found {users} filtered users {users_filtered}"
f"No users found for server 2 {server_2_type}, users found {users} filtered users {users_filtered}, server 2 users {server_2_connection.users}"
)
logger(f"Server 1 users: {output_server_1_users}", 1)

View File

@@ -1,4 +1,4 @@
import re, requests
import re, requests, os, traceback
from urllib3.poolmanager import PoolManager
from plexapi.server import PlexServer
@@ -24,6 +24,52 @@ class HostNameIgnoringAdapter(requests.adapters.HTTPAdapter):
)
def get_user_library_watched_show(show):
try:
show_guids = {}
for show_guid in show.guids:
# Extract source and id from guid.id
m = re.match(r"(.*)://(.*)", show_guid.id)
show_guid_source, show_guid_id = m.group(1).lower(), m.group(2)
show_guids[show_guid_source] = show_guid_id
show_guids["title"] = show.title
show_guids["locations"] = tuple([x.split("/")[-1] for x in show.locations])
show_guids = frozenset(show_guids.items())
# Get all watched episodes for show
episode_guids = {}
watched_episodes = show.watched()
for episode in watched_episodes:
episode_guids_temp = {}
try:
if len(episode.guids) > 0:
for guid in episode.guids:
# Extract after :// from guid.id
m = re.match(r"(.*)://(.*)", guid.id)
guid_source, guid_id = m.group(1).lower(), m.group(2)
episode_guids_temp[guid_source] = guid_id
except:
logger(
f"Plex: Failed to get guids for {episode.title} in {show.title}, Using location only",
1,
)
episode_guids_temp["locations"] = tuple(
[x.split("/")[-1] for x in episode.locations]
)
if episode.parentTitle not in episode_guids:
episode_guids[episode.parentTitle] = []
episode_guids[episode.parentTitle].append(episode_guids_temp)
return show_guids, episode_guids
except Exception as e:
return {}, {}
def get_user_library_watched(user, user_plex, library):
try:
user_name = user.title.lower()
@@ -61,41 +107,17 @@ def get_user_library_watched(user, user_plex, library):
elif library.type == "show":
user_watched[user_name][library.title] = {}
shows = library_videos.search(unwatched=False)
for show in library_videos.search(unwatched=False):
logger(f"Plex: Adding {show.title} to {user_name} watched list", 3)
show_guids = {}
for show_guid in show.guids:
# Extract source and id from guid.id
m = re.match(r"(.*)://(.*)", show_guid.id)
show_guid_source, show_guid_id = m.group(1).lower(), m.group(2)
show_guids[show_guid_source] = show_guid_id
# Parallelize show processing
args = []
for show in shows:
args.append([get_user_library_watched_show, show])
show_guids["title"] = show.title
show_guids["locations"] = tuple(
[x.split("/")[-1] for x in show.locations]
)
show_guids = frozenset(show_guids.items())
# Get all watched episodes for show
episode_guids = {}
for episode in show.watched():
if episode.viewCount > 0:
episode_guids_temp = {}
for guid in episode.guids:
# Extract after :// from guid.id
m = re.match(r"(.*)://(.*)", guid.id)
guid_source, guid_id = m.group(1).lower(), m.group(2)
episode_guids_temp[guid_source] = guid_id
episode_guids_temp["locations"] = tuple(
[x.split("/")[-1] for x in episode.locations]
)
if episode.parentTitle not in episode_guids:
episode_guids[episode.parentTitle] = []
episode_guids[episode.parentTitle].append(episode_guids_temp)
if episode_guids:
for show_guids, episode_guids in future_thread_executor(
args, workers=min(os.cpu_count(), 4)
):
if show_guids and episode_guids:
# append show, season, episode
if show_guids not in user_watched[user_name][library.title]:
user_watched[user_name][library.title][show_guids] = {}
@@ -116,7 +138,7 @@ def get_user_library_watched(user, user_plex, library):
f"Plex: Failed to get watched for {user_name} in library {library.title}, Error: {e}",
2,
)
raise Exception(e)
return {}
def update_user_watched(user, user_plex, library, videos, dryrun):
@@ -201,24 +223,30 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
break
if not episode_found:
for episode_guid in episode_search.guids:
episode_guid_source = (
re.search(r"(.*)://", episode_guid.id)
.group(1)
.lower()
)
episode_guid_id = re.search(
r"://(.*)", episode_guid.id
).group(1)
try:
for episode_guid in episode_search.guids:
episode_guid_source = (
re.search(r"(.*)://", episode_guid.id)
.group(1)
.lower()
)
episode_guid_id = re.search(
r"://(.*)", episode_guid.id
).group(1)
# If episode provider source and episode provider id are in videos_episodes_ids exactly, then the episode is in the list
if episode_guid_source in videos_episodes_ids.keys():
if (
episode_guid_id
in videos_episodes_ids[episode_guid_source]
):
episode_found = True
break
# If episode provider source and episode provider id are in videos_episodes_ids exactly, then the episode is in the list
if episode_guid_source in videos_episodes_ids.keys():
if (
episode_guid_id
in videos_episodes_ids[episode_guid_source]
):
episode_found = True
break
except Exception as e:
logger(
f"Plex: Failed to get episode guid for {episode_search.title}, Error: {e}",
1,
)
if episode_found:
msg = f"{show_search.title} {episode_search.title} as watched for {user.title} in {library} for Plex"
@@ -249,7 +277,7 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
f"Plex: Failed to update watched for {user.title} in library {library}, Error: {e}",
2,
)
raise Exception(e)
logger(traceback.format_exc(), 2)
# class plex accept base url and token and username and password but default with none
@@ -262,6 +290,7 @@ class Plex:
password=None,
servername=None,
ssl_bypass=False,
session=None,
):
self.baseurl = baseurl
self.token = token
@@ -269,21 +298,20 @@ class Plex:
self.password = password
self.servername = servername
self.ssl_bypass = ssl_bypass
self.plex = self.login(self.baseurl, self.token, ssl_bypass)
if ssl_bypass:
# Session for ssl bypass
session = requests.Session()
# By pass ssl hostname check https://github.com/pkkid/python-plexapi/issues/143#issuecomment-775485186
session.mount("https://", HostNameIgnoringAdapter())
self.session = session
self.plex = self.login(self.baseurl, self.token)
self.admin_user = self.plex.myPlexAccount()
self.users = self.get_users()
def login(self, baseurl, token, ssl_bypass=False):
def login(self, baseurl, token):
try:
if baseurl and token:
# Login via token
if ssl_bypass:
session = requests.Session()
# By pass ssl hostname check https://github.com/pkkid/python-plexapi/issues/143#issuecomment-775485186
session.mount("https://", HostNameIgnoringAdapter())
plex = PlexServer(baseurl, token, session=session)
else:
plex = PlexServer(baseurl, token)
plex = PlexServer(baseurl, token, session=self.session)
elif self.username and self.password and self.servername:
# Login via plex account
account = MyPlexAccount(self.username, self.password)
@@ -333,7 +361,6 @@ class Plex:
user_plex = self.login(
self.plex._baseurl,
user.get_token(self.plex.machineIdentifier),
self.ssl_bypass,
)
libraries = user_plex.library.sections()
@@ -397,8 +424,17 @@ class Plex:
if self.admin_user == user:
user_plex = self.plex
else:
if isinstance(user, str):
logger(
f"Plex: {user} is not a plex object, attempting to get object for user",
4,
)
user = self.plex.myPlexAccount().user(user)
user_plex = PlexServer(
self.plex._baseurl, user.get_token(self.plex.machineIdentifier)
self.plex._baseurl,
user.get_token(self.plex.machineIdentifier),
session=self.session,
)
for library, videos in libraries.items():