commit
7571e9a343
|
|
@ -80,13 +80,12 @@ def check_skip_logic(library_title, library_type, blacklist_library, whitelist_l
|
|||
return skip_reason
|
||||
|
||||
|
||||
def generate_library_guids_dict(user_list: dict, generate_output: int):
|
||||
# if generate_output is 0 then only generate shows, if 1 then only generate episodes, if 2 then generate movies, if 3 then generate shows and episodes
|
||||
def generate_library_guids_dict(user_list: dict):
|
||||
show_output_dict = {}
|
||||
episode_output_dict = {}
|
||||
movies_output_dict = {}
|
||||
|
||||
if generate_output in (0, 3):
|
||||
try:
|
||||
show_output_keys = user_list.keys()
|
||||
show_output_keys = ([ dict(x) for x in list(show_output_keys) ])
|
||||
for show_key in show_output_keys:
|
||||
|
|
@ -101,8 +100,10 @@ def generate_library_guids_dict(user_list: dict, generate_output: int):
|
|||
show_output_dict[provider_key.lower()].append(show_location)
|
||||
else:
|
||||
show_output_dict[provider_key.lower()].append(provider_value.lower())
|
||||
except:
|
||||
pass
|
||||
|
||||
if generate_output in (1, 3):
|
||||
try:
|
||||
for show in user_list:
|
||||
for season in user_list[show]:
|
||||
for episode in user_list[show][season]:
|
||||
|
|
@ -114,8 +115,10 @@ def generate_library_guids_dict(user_list: dict, generate_output: int):
|
|||
episode_output_dict[episode_key.lower()].append(episode_location)
|
||||
else:
|
||||
episode_output_dict[episode_key.lower()].append(episode_value.lower())
|
||||
except:
|
||||
pass
|
||||
|
||||
if generate_output == 2:
|
||||
try:
|
||||
for movie in user_list:
|
||||
for movie_key, movie_value in movie.items():
|
||||
if movie_key.lower() not in movies_output_dict:
|
||||
|
|
@ -125,6 +128,8 @@ def generate_library_guids_dict(user_list: dict, generate_output: int):
|
|||
movies_output_dict[movie_key.lower()].append(movie_location)
|
||||
else:
|
||||
movies_output_dict[movie_key.lower()].append(movie_value.lower())
|
||||
except:
|
||||
pass
|
||||
|
||||
return show_output_dict, episode_output_dict, movies_output_dict
|
||||
|
||||
|
|
|
|||
|
|
@ -162,16 +162,14 @@ class Jellyfin():
|
|||
logger(f"Jellyfin: Failed to get watched, Error: {e}", 2)
|
||||
raise Exception(e)
|
||||
|
||||
def update_user_watched(self, user, user_id, library, library_id, videos, dryrun):
|
||||
def update_user_watched(self, user_name, user_id, library, library_id, videos, dryrun):
|
||||
try:
|
||||
logger(f"Jellyfin: Updating watched for {user} in library {library}", 1)
|
||||
library_search = self.query(f"/Users/{user_id}/Items?SortBy=SortName&SortOrder=Ascending&Recursive=true&ParentId={library_id}&limit=1", "get")
|
||||
library_type = library_search["Items"][0]["Type"]
|
||||
logger(f"Jellyfin: Updating watched for {user_name} in library {library}", 1)
|
||||
videos_shows_ids, videos_episodes_ids, videos_movies_ids = generate_library_guids_dict(videos)
|
||||
|
||||
# Movies
|
||||
if library_type == "Movie":
|
||||
_, _, videos_movies_ids = generate_library_guids_dict(videos, 2)
|
||||
logger(f"Jellyfin: mark list\nShows: {videos_shows_ids}\nEpisodes: {videos_episodes_ids}\nMovies: {videos_movies_ids}", 1)
|
||||
|
||||
if videos_movies_ids:
|
||||
jellyfin_search = self.query(f"/Users/{user_id}/Items?SortBy=SortName&SortOrder=Ascending&Recursive=false&ParentId={library_id}&isPlayed=false&Fields=ItemCounts,ProviderIds,MediaSources", "get")
|
||||
for jellyfin_video in jellyfin_search["Items"]:
|
||||
movie_found = False
|
||||
|
|
@ -191,27 +189,25 @@ class Jellyfin():
|
|||
|
||||
if movie_found:
|
||||
jellyfin_video_id = jellyfin_video["Id"]
|
||||
msg = f"{jellyfin_video['Name']} as watched for {user} in {library} for Jellyfin"
|
||||
msg = f"{jellyfin_video['Name']} as watched for {user_name} in {library} for Jellyfin"
|
||||
if not dryrun:
|
||||
logger(f"Marking {msg}", 0)
|
||||
self.query(f"/Users/{user_id}/PlayedItems/{jellyfin_video_id}", "post")
|
||||
else:
|
||||
logger(f"Dryrun {msg}", 0)
|
||||
else:
|
||||
logger(f"Jellyfin: Skipping movie {jellyfin_video['Name']} as it is not in mark list for {user_name}", 1)
|
||||
|
||||
|
||||
|
||||
# TV Shows
|
||||
if library_type == "Episode":
|
||||
videos_shows_ids, videos_episode_ids, _ = generate_library_guids_dict(videos, 3)
|
||||
|
||||
if videos_shows_ids and videos_episodes_ids:
|
||||
jellyfin_search = self.query(f"/Users/{user_id}/Items?SortBy=SortName&SortOrder=Ascending&Recursive=false&ParentId={library_id}&isPlayed=false&Fields=ItemCounts,ProviderIds,Path", "get")
|
||||
jellyfin_shows = [x for x in jellyfin_search["Items"]]
|
||||
|
||||
for jellyfin_show in jellyfin_shows:
|
||||
show_found = False
|
||||
|
||||
if jellyfin_show["Name"] == "The 13 Ghosts of Scooby-Doo":
|
||||
print(jellyfin_show)
|
||||
|
||||
if "Path" in jellyfin_show:
|
||||
if jellyfin_show["Path"].split("/")[-1] in videos_shows_ids["locations"]:
|
||||
show_found = True
|
||||
|
|
@ -224,6 +220,7 @@ class Jellyfin():
|
|||
break
|
||||
|
||||
if show_found:
|
||||
logger(f"Jellyfin: Updating watched for {user_name} in library {library} for show {jellyfin_show['Name']}", 1)
|
||||
jellyfin_show_id = jellyfin_show["Id"]
|
||||
jellyfin_episodes = self.query(f"/Shows/{jellyfin_show_id}/Episodes?userId={user_id}&Fields=ItemCounts,ProviderIds,MediaSources", "get")
|
||||
|
||||
|
|
@ -232,28 +229,35 @@ class Jellyfin():
|
|||
|
||||
if "MediaSources" in jellyfin_episode:
|
||||
for episode_location in jellyfin_episode["MediaSources"]:
|
||||
if episode_location["Path"].split("/")[-1] in videos_episode_ids["locations"]:
|
||||
if episode_location["Path"].split("/")[-1] in videos_episodes_ids["locations"]:
|
||||
episode_found = True
|
||||
break
|
||||
|
||||
if not episode_found:
|
||||
for episode_provider_source, episode_provider_id in jellyfin_episode["ProviderIds"].items():
|
||||
if episode_provider_source.lower() in videos_episode_ids:
|
||||
if episode_provider_id.lower() in videos_episode_ids[episode_provider_source.lower()]:
|
||||
if episode_provider_source.lower() in videos_episodes_ids:
|
||||
if episode_provider_id.lower() in videos_episodes_ids[episode_provider_source.lower()]:
|
||||
episode_found = True
|
||||
break
|
||||
|
||||
if episode_found:
|
||||
jellyfin_episode_id = jellyfin_episode["Id"]
|
||||
msg = f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode['IndexNumber']} {jellyfin_episode['Name']} as watched for {user} in {library} for Jellyfin"
|
||||
msg = f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode['Name']} as watched for {user_name} in {library} for Jellyfin"
|
||||
if not dryrun:
|
||||
logger(f"Marked {msg}", 0)
|
||||
self.query(f"/Users/{user_id}/PlayedItems/{jellyfin_episode_id}", "post")
|
||||
else:
|
||||
logger(f"Dryrun {msg}", 0)
|
||||
else:
|
||||
logger(f"Jellyfin: Skipping episode {jellyfin_episode['Name']} as it is not in mark list for {user_name}", 1)
|
||||
else:
|
||||
logger(f"Jellyfin: Skipping show {jellyfin_show['Name']} as it is not in mark list for {user_name}", 1)
|
||||
|
||||
if not videos_movies_ids and not videos_shows_ids and not videos_episodes_ids:
|
||||
logger(f"Jellyfin: No videos to mark as watched for {user_name} in library {library}", 1)
|
||||
|
||||
except Exception as e:
|
||||
logger(f"Jellyfin: Error updating watched for {user} in library {library}", 2)
|
||||
logger(f"Jellyfin: Error updating watched for {user_name} in library {library}", 2)
|
||||
raise Exception(e)
|
||||
|
||||
|
||||
|
|
@ -261,7 +265,9 @@ class Jellyfin():
|
|||
try:
|
||||
args = []
|
||||
for user, libraries in watched_list.items():
|
||||
logger(f"Jellyfin: Updating for entry {user}, {libraries}", 1)
|
||||
user_other = None
|
||||
user_name = None
|
||||
if user_mapping:
|
||||
if user in user_mapping.keys():
|
||||
user_other = user_mapping[user]
|
||||
|
|
@ -272,9 +278,11 @@ class Jellyfin():
|
|||
for key in self.users.keys():
|
||||
if user.lower() == key.lower():
|
||||
user_id = self.users[key]
|
||||
user_name = key
|
||||
break
|
||||
elif user_other and user_other.lower() == key.lower():
|
||||
user_id = self.users[key]
|
||||
user_name = key
|
||||
break
|
||||
|
||||
if not user_id:
|
||||
|
|
@ -311,7 +319,7 @@ class Jellyfin():
|
|||
continue
|
||||
|
||||
if library_id:
|
||||
args.append([self.update_user_watched, user, user_id, library, library_id, videos, dryrun])
|
||||
args.append([self.update_user_watched, user_name, user_id, library, library_id, videos, dryrun])
|
||||
|
||||
future_thread_executor(args)
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ def cleanup_watched(watched_list_1, watched_list_2, user_mapping=None, library_m
|
|||
|
||||
# Movies
|
||||
if isinstance(watched_list_1[user_1][library_1], list):
|
||||
_, _, movies_watched_list_2_keys_dict = generate_library_guids_dict(watched_list_2[user_2][library_2], 2)
|
||||
_, _, movies_watched_list_2_keys_dict = generate_library_guids_dict(watched_list_2[user_2][library_2])
|
||||
for movie in watched_list_1[user_1][library_1]:
|
||||
movie_found = False
|
||||
for movie_key, movie_value in movie.items():
|
||||
|
|
@ -63,7 +63,7 @@ def cleanup_watched(watched_list_1, watched_list_2, user_mapping=None, library_m
|
|||
# TV Shows
|
||||
elif isinstance(watched_list_1[user_1][library_1], dict):
|
||||
# Generate full list of provider ids for episodes in watch_list_2 to easily compare if they exist in watch_list_1
|
||||
show_watched_list_2_keys_dict, episode_watched_list_2_keys_dict, _ = generate_library_guids_dict(watched_list_2[user_2][library_2], 3)
|
||||
_, episode_watched_list_2_keys_dict, _ = generate_library_guids_dict(watched_list_2[user_2][library_2])
|
||||
|
||||
for show_key_1 in watched_list_1[user_1][library_1].keys():
|
||||
show_key_dict = dict(show_key_1)
|
||||
|
|
@ -85,14 +85,14 @@ def cleanup_watched(watched_list_1, watched_list_2, user_mapping=None, library_m
|
|||
|
||||
if episode_found:
|
||||
if episode in modified_watched_list_1[user_1][library_1][show_key_1][season]:
|
||||
logger(f"Removing {show_key_dict['title']} {episode} from {library_1}", 3)
|
||||
logger(f"Removing {episode} from {show_key_dict['title']}", 3)
|
||||
modified_watched_list_1[user_1][library_1][show_key_1][season].remove(episode)
|
||||
break
|
||||
|
||||
# Remove empty seasons
|
||||
if len(modified_watched_list_1[user_1][library_1][show_key_1][season]) == 0:
|
||||
if season in modified_watched_list_1[user_1][library_1][show_key_1]:
|
||||
logger(f"Removing {season} from {library_1} because it is empty", 3)
|
||||
logger(f"Removing {season} from {show_key_dict['title']} because it is empty", 3)
|
||||
del modified_watched_list_1[user_1][library_1][show_key_1][season]
|
||||
|
||||
# If the show is empty, remove the show
|
||||
|
|
|
|||
59
src/plex.py
59
src/plex.py
|
|
@ -1,4 +1,4 @@
|
|||
import re
|
||||
import re, requests
|
||||
|
||||
from plexapi.server import PlexServer
|
||||
from plexapi.myplex import MyPlexAccount
|
||||
|
|
@ -8,7 +8,7 @@ from src.functions import logger, search_mapping, check_skip_logic, generate_lib
|
|||
|
||||
# class plex accept base url and token and username and password but default with none
|
||||
class Plex:
|
||||
def __init__(self, baseurl=None, token=None, username=None, password=None, servername=None):
|
||||
def __init__(self, baseurl=None, token=None, username=None, password=None, servername=None, ssl_bypass=False):
|
||||
self.baseurl = baseurl
|
||||
self.token = token
|
||||
self.username = username
|
||||
|
|
@ -162,10 +162,11 @@ class Plex:
|
|||
def update_user_watched (self, user, user_plex, library, videos, dryrun):
|
||||
try:
|
||||
logger(f"Plex: Updating watched for {user.title} in library {library}", 1)
|
||||
library_videos = user_plex.library.section(library)
|
||||
videos_shows_ids, videos_episodes_ids, videos_movies_ids = generate_library_guids_dict(videos)
|
||||
logger(f"Plex: mark list\nShows: {videos_shows_ids}\nEpisodes: {videos_episodes_ids}\nMovies: {videos_movies_ids}", 1)
|
||||
|
||||
if library_videos.type == "movie":
|
||||
_, _, videos_movies_ids = generate_library_guids_dict(videos, 2)
|
||||
library_videos = user_plex.library.section(library)
|
||||
if videos_movies_ids:
|
||||
for movies_search in library_videos.search(unwatched=True):
|
||||
movie_found = False
|
||||
for movie_location in movies_search.locations:
|
||||
|
|
@ -185,18 +186,17 @@ class Plex:
|
|||
break
|
||||
|
||||
if movie_found:
|
||||
if movies_search.viewCount == 0:
|
||||
msg = f"{movies_search.title} as watched for {user.title} in {library} for Plex"
|
||||
if not dryrun:
|
||||
logger(f"Marked {msg}", 0)
|
||||
movies_search.markWatched()
|
||||
else:
|
||||
logger(f"Dryrun {msg}", 0)
|
||||
msg = f"{movies_search.title} as watched for {user.title} in {library} for Plex"
|
||||
if not dryrun:
|
||||
logger(f"Marked {msg}", 0)
|
||||
movies_search.markWatched()
|
||||
else:
|
||||
logger(f"Dryrun {msg}", 0)
|
||||
else:
|
||||
logger(f"Plex: Skipping movie {movies_search.title} as it is not in mark list for {user.title}", 1)
|
||||
|
||||
|
||||
elif library_videos.type == "show":
|
||||
videos_shows_ids, videos_episode_ids, _ = generate_library_guids_dict(videos, 3)
|
||||
|
||||
if videos_shows_ids and videos_episodes_ids:
|
||||
for show_search in library_videos.search(unwatched=True):
|
||||
show_found = False
|
||||
for show_location in show_search.locations:
|
||||
|
|
@ -220,7 +220,7 @@ class Plex:
|
|||
episode_found = False
|
||||
|
||||
for episode_location in episode_search.locations:
|
||||
if episode_location.split("/")[-1] in videos_episode_ids["locations"]:
|
||||
if episode_location.split("/")[-1] in videos_episodes_ids["locations"]:
|
||||
episode_found = True
|
||||
break
|
||||
|
||||
|
|
@ -229,20 +229,27 @@ class Plex:
|
|||
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_episode_ids exactly, then the episode is in the list
|
||||
if episode_guid_source in videos_episode_ids.keys():
|
||||
if episode_guid_id in videos_episode_ids[episode_guid_source]:
|
||||
# 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_found:
|
||||
if episode_search.viewCount == 0:
|
||||
msg = f"{show_search.title} {episode_search.title} as watched for {user.title} in {library} for Plex"
|
||||
if not dryrun:
|
||||
logger(f"Marked {msg}", 0)
|
||||
episode_search.markWatched()
|
||||
else:
|
||||
logger(f"Dryrun {msg}", 0)
|
||||
msg = f"{show_search.title} {episode_search.title} as watched for {user.title} in {library} for Plex"
|
||||
if not dryrun:
|
||||
logger(f"Marked {msg}", 0)
|
||||
episode_search.markWatched()
|
||||
else:
|
||||
logger(f"Dryrun {msg}", 0)
|
||||
else:
|
||||
logger(f"Plex: Skipping episode {episode_search.title} as it is not in mark list for {user.title}", 1)
|
||||
else:
|
||||
logger(f"Plex: Skipping show {show_search.title} as it is not in mark list for {user.title}", 1)
|
||||
|
||||
if not videos_movies_ids and not videos_shows_ids and not videos_episodes_ids:
|
||||
logger(f"Jellyfin: No videos to mark as watched for {user.title} in library {library}", 1)
|
||||
|
||||
except Exception as e:
|
||||
logger(f"Plex: Failed to update watched for {user.title} in library {library}, Error: {e}", 2)
|
||||
raise Exception(e)
|
||||
|
|
|
|||
Loading…
Reference in New Issue