commit
654e7f20e1
|
|
@ -6,16 +6,16 @@ ENV DEBUG_LEVEL 'INFO'
|
||||||
ENV SLEEP_DURATION '3600'
|
ENV SLEEP_DURATION '3600'
|
||||||
ENV LOGFILE 'log.log'
|
ENV LOGFILE 'log.log'
|
||||||
|
|
||||||
ENV USER_MAPPING '{ "User Test": "User Test2" }'
|
ENV USER_MAPPING ''
|
||||||
ENV LIBRARY_MAPPING '{ "Shows Test": "TV Shows Test" }'
|
ENV LIBRARY_MAPPING ''
|
||||||
|
|
||||||
ENV PLEX_BASEURL 'http://localhost:32400'
|
ENV PLEX_BASEURL ''
|
||||||
ENV PLEX_TOKEN ''
|
ENV PLEX_TOKEN ''
|
||||||
ENV PLEX_USERNAME ''
|
ENV PLEX_USERNAME ''
|
||||||
ENV PLEX_PASSWORD ''
|
ENV PLEX_PASSWORD ''
|
||||||
ENV PLEX_SERVERNAME ''
|
ENV PLEX_SERVERNAME ''
|
||||||
|
|
||||||
ENV JELLYFIN_BASEURL 'http://localhost:8096'
|
ENV JELLYFIN_BASEURL ''
|
||||||
ENV JELLYFIN_TOKEN ''
|
ENV JELLYFIN_TOKEN ''
|
||||||
|
|
||||||
ENV BLACKLIST_LIBRARY ''
|
ENV BLACKLIST_LIBRARY ''
|
||||||
|
|
|
||||||
288
src/functions.py
288
src/functions.py
|
|
@ -1,4 +1,4 @@
|
||||||
import os
|
import os, copy
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
@ -8,13 +8,13 @@ logfile = os.getenv("LOGFILE", "log.log")
|
||||||
|
|
||||||
|
|
||||||
def logger(message: str, log_type=0):
|
def logger(message: str, log_type=0):
|
||||||
debug = str_to_bool(os.getenv("DEBUG", "True"))
|
debug = str_to_bool(os.getenv("DEBUG", "False"))
|
||||||
debug_level = os.getenv("DEBUG_LEVEL", "info").lower()
|
debug_level = os.getenv("DEBUG_LEVEL", "info").lower()
|
||||||
|
|
||||||
output = str(message)
|
output = str(message)
|
||||||
if log_type == 0:
|
if log_type == 0:
|
||||||
pass
|
pass
|
||||||
elif log_type == 1 and (debug and debug_level == "info"):
|
elif log_type == 1 and (debug and debug_level in ("info", "debug")):
|
||||||
output = f"[INFO]: {output}"
|
output = f"[INFO]: {output}"
|
||||||
elif log_type == 2:
|
elif log_type == 2:
|
||||||
output = f"[ERROR]: {output}"
|
output = f"[ERROR]: {output}"
|
||||||
|
|
@ -55,6 +55,108 @@ def search_mapping(dictionary: dict, key_value: str):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def setup_black_white_lists(
|
||||||
|
blacklist_library: str,
|
||||||
|
whitelist_library: str,
|
||||||
|
blacklist_library_type: str,
|
||||||
|
whitelist_library_type: str,
|
||||||
|
blacklist_users: str,
|
||||||
|
whitelist_users: str,
|
||||||
|
library_mapping=None,
|
||||||
|
user_mapping=None,
|
||||||
|
):
|
||||||
|
if blacklist_library:
|
||||||
|
if len(blacklist_library) > 0:
|
||||||
|
blacklist_library = blacklist_library.split(",")
|
||||||
|
blacklist_library = [x.strip() for x in blacklist_library]
|
||||||
|
if library_mapping:
|
||||||
|
temp_library = []
|
||||||
|
for library in blacklist_library:
|
||||||
|
library_other = search_mapping(library_mapping, library)
|
||||||
|
if library_other:
|
||||||
|
temp_library.append(library_other)
|
||||||
|
|
||||||
|
blacklist_library = blacklist_library + temp_library
|
||||||
|
else:
|
||||||
|
blacklist_library = []
|
||||||
|
logger(f"Blacklist Library: {blacklist_library}", 1)
|
||||||
|
|
||||||
|
if whitelist_library:
|
||||||
|
if len(whitelist_library) > 0:
|
||||||
|
whitelist_library = whitelist_library.split(",")
|
||||||
|
whitelist_library = [x.strip() for x in whitelist_library]
|
||||||
|
if library_mapping:
|
||||||
|
temp_library = []
|
||||||
|
for library in whitelist_library:
|
||||||
|
library_other = search_mapping(library_mapping, library)
|
||||||
|
if library_other:
|
||||||
|
temp_library.append(library_other)
|
||||||
|
|
||||||
|
whitelist_library = whitelist_library + temp_library
|
||||||
|
else:
|
||||||
|
whitelist_library = []
|
||||||
|
logger(f"Whitelist Library: {whitelist_library}", 1)
|
||||||
|
|
||||||
|
if blacklist_library_type:
|
||||||
|
if len(blacklist_library_type) > 0:
|
||||||
|
blacklist_library_type = blacklist_library_type.split(",")
|
||||||
|
blacklist_library_type = [x.lower().strip() for x in blacklist_library_type]
|
||||||
|
else:
|
||||||
|
blacklist_library_type = []
|
||||||
|
logger(f"Blacklist Library Type: {blacklist_library_type}", 1)
|
||||||
|
|
||||||
|
if whitelist_library_type:
|
||||||
|
if len(whitelist_library_type) > 0:
|
||||||
|
whitelist_library_type = whitelist_library_type.split(",")
|
||||||
|
whitelist_library_type = [x.lower().strip() for x in whitelist_library_type]
|
||||||
|
else:
|
||||||
|
whitelist_library_type = []
|
||||||
|
logger(f"Whitelist Library Type: {whitelist_library_type}", 1)
|
||||||
|
|
||||||
|
if blacklist_users:
|
||||||
|
if len(blacklist_users) > 0:
|
||||||
|
blacklist_users = blacklist_users.split(",")
|
||||||
|
blacklist_users = [x.lower().strip() for x in blacklist_users]
|
||||||
|
if user_mapping:
|
||||||
|
temp_users = []
|
||||||
|
for user in blacklist_users:
|
||||||
|
user_other = search_mapping(user_mapping, user)
|
||||||
|
if user_other:
|
||||||
|
temp_users.append(user_other)
|
||||||
|
|
||||||
|
blacklist_users = blacklist_users + temp_users
|
||||||
|
else:
|
||||||
|
blacklist_users = []
|
||||||
|
logger(f"Blacklist Users: {blacklist_users}", 1)
|
||||||
|
|
||||||
|
if whitelist_users:
|
||||||
|
if len(whitelist_users) > 0:
|
||||||
|
whitelist_users = whitelist_users.split(",")
|
||||||
|
whitelist_users = [x.lower().strip() for x in whitelist_users]
|
||||||
|
if user_mapping:
|
||||||
|
temp_users = []
|
||||||
|
for user in whitelist_users:
|
||||||
|
user_other = search_mapping(user_mapping, user)
|
||||||
|
if user_other:
|
||||||
|
temp_users.append(user_other)
|
||||||
|
|
||||||
|
whitelist_users = whitelist_users + temp_users
|
||||||
|
else:
|
||||||
|
whitelist_users = []
|
||||||
|
else:
|
||||||
|
whitelist_users = []
|
||||||
|
logger(f"Whitelist Users: {whitelist_users}", 1)
|
||||||
|
|
||||||
|
return (
|
||||||
|
blacklist_library,
|
||||||
|
whitelist_library,
|
||||||
|
blacklist_library_type,
|
||||||
|
whitelist_library_type,
|
||||||
|
blacklist_users,
|
||||||
|
whitelist_users,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_skip_logic(
|
def check_skip_logic(
|
||||||
library_title,
|
library_title,
|
||||||
library_type,
|
library_type,
|
||||||
|
|
@ -100,6 +202,10 @@ def generate_library_guids_dict(user_list: dict):
|
||||||
episode_output_dict = {}
|
episode_output_dict = {}
|
||||||
movies_output_dict = {}
|
movies_output_dict = {}
|
||||||
|
|
||||||
|
# Handle the case where user_list is empty or does not contain the expected keys and values
|
||||||
|
if not user_list:
|
||||||
|
return show_output_dict, episode_output_dict, movies_output_dict
|
||||||
|
|
||||||
try:
|
try:
|
||||||
show_output_keys = user_list.keys()
|
show_output_keys = user_list.keys()
|
||||||
show_output_keys = [dict(x) for x in list(show_output_keys)]
|
show_output_keys = [dict(x) for x in list(show_output_keys)]
|
||||||
|
|
@ -162,17 +268,189 @@ def combine_watched_dicts(dicts: list):
|
||||||
if key not in combined_dict:
|
if key not in combined_dict:
|
||||||
combined_dict[key] = {}
|
combined_dict[key] = {}
|
||||||
for subkey, subvalue in value.items():
|
for subkey, subvalue in value.items():
|
||||||
combined_dict[key][subkey] = subvalue
|
if subkey in combined_dict[key]:
|
||||||
|
# If the subkey already exists in the combined dictionary,
|
||||||
|
# check if the values are different and raise an exception if they are
|
||||||
|
if combined_dict[key][subkey] != subvalue:
|
||||||
|
raise ValueError(
|
||||||
|
f"Conflicting values for subkey '{subkey}' under key '{key}'"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# If the subkey does not exist in the combined dictionary, add it
|
||||||
|
combined_dict[key][subkey] = subvalue
|
||||||
|
|
||||||
return combined_dict
|
return combined_dict
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_watched(
|
||||||
|
watched_list_1, watched_list_2, user_mapping=None, library_mapping=None
|
||||||
|
):
|
||||||
|
modified_watched_list_1 = copy.deepcopy(watched_list_1)
|
||||||
|
|
||||||
|
# remove entries from watched_list_1 that are in watched_list_2
|
||||||
|
for user_1 in watched_list_1:
|
||||||
|
user_other = None
|
||||||
|
if user_mapping:
|
||||||
|
user_other = search_mapping(user_mapping, user_1)
|
||||||
|
user_2 = get_other(watched_list_2, user_1, user_other)
|
||||||
|
if user_2 is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for library_1 in watched_list_1[user_1]:
|
||||||
|
library_other = None
|
||||||
|
if library_mapping:
|
||||||
|
library_other = search_mapping(library_mapping, library_1)
|
||||||
|
library_2 = get_other(watched_list_2[user_2], library_1, library_other)
|
||||||
|
if library_2 is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
(
|
||||||
|
_,
|
||||||
|
episode_watched_list_2_keys_dict,
|
||||||
|
movies_watched_list_2_keys_dict,
|
||||||
|
) = generate_library_guids_dict(watched_list_2[user_2][library_2])
|
||||||
|
|
||||||
|
# Movies
|
||||||
|
if isinstance(watched_list_1[user_1][library_1], list):
|
||||||
|
for movie in watched_list_1[user_1][library_1]:
|
||||||
|
if is_movie_in_dict(movie, movies_watched_list_2_keys_dict):
|
||||||
|
logger(f"Removing {movie} from {library_1}", 3)
|
||||||
|
modified_watched_list_1[user_1][library_1].remove(movie)
|
||||||
|
|
||||||
|
# TV Shows
|
||||||
|
elif isinstance(watched_list_1[user_1][library_1], dict):
|
||||||
|
for show_key_1 in watched_list_1[user_1][library_1].keys():
|
||||||
|
show_key_dict = dict(show_key_1)
|
||||||
|
for season in watched_list_1[user_1][library_1][show_key_1]:
|
||||||
|
for episode in watched_list_1[user_1][library_1][show_key_1][
|
||||||
|
season
|
||||||
|
]:
|
||||||
|
if is_episode_in_dict(
|
||||||
|
episode, episode_watched_list_2_keys_dict
|
||||||
|
):
|
||||||
|
if (
|
||||||
|
episode
|
||||||
|
in modified_watched_list_1[user_1][library_1][
|
||||||
|
show_key_1
|
||||||
|
][season]
|
||||||
|
):
|
||||||
|
logger(
|
||||||
|
f"Removing {episode} from {show_key_dict['title']}",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
modified_watched_list_1[user_1][library_1][
|
||||||
|
show_key_1
|
||||||
|
][season].remove(episode)
|
||||||
|
|
||||||
|
# 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 {show_key_dict['title']} because it is empty",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
del modified_watched_list_1[user_1][library_1][
|
||||||
|
show_key_1
|
||||||
|
][season]
|
||||||
|
|
||||||
|
# Remove empty shows
|
||||||
|
if len(modified_watched_list_1[user_1][library_1][show_key_1]) == 0:
|
||||||
|
if show_key_1 in modified_watched_list_1[user_1][library_1]:
|
||||||
|
logger(
|
||||||
|
f"Removing {show_key_dict['title']} because it is empty",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
del modified_watched_list_1[user_1][library_1][show_key_1]
|
||||||
|
|
||||||
|
for user_1 in watched_list_1:
|
||||||
|
for library_1 in watched_list_1[user_1]:
|
||||||
|
if library_1 in modified_watched_list_1[user_1]:
|
||||||
|
# If library is empty then remove it
|
||||||
|
if len(modified_watched_list_1[user_1][library_1]) == 0:
|
||||||
|
logger(f"Removing {library_1} from {user_1} because it is empty", 1)
|
||||||
|
del modified_watched_list_1[user_1][library_1]
|
||||||
|
|
||||||
|
if user_1 in modified_watched_list_1:
|
||||||
|
# If user is empty delete user
|
||||||
|
if len(modified_watched_list_1[user_1]) == 0:
|
||||||
|
logger(f"Removing {user_1} from watched list 1 because it is empty", 1)
|
||||||
|
del modified_watched_list_1[user_1]
|
||||||
|
|
||||||
|
return modified_watched_list_1
|
||||||
|
|
||||||
|
|
||||||
|
def get_other(watched_list_2, object_1, object_2):
|
||||||
|
if object_1 in watched_list_2:
|
||||||
|
return object_1
|
||||||
|
elif object_2 in watched_list_2:
|
||||||
|
return object_2
|
||||||
|
else:
|
||||||
|
logger(f"{object_1} and {object_2} not found in watched list 2", 1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_movie_in_dict(movie, movies_watched_list_2_keys_dict):
|
||||||
|
# Iterate through the keys and values of the movie dictionary
|
||||||
|
for movie_key, movie_value in movie.items():
|
||||||
|
# If the key is "locations", check if the "locations" key is present in the movies_watched_list_2_keys_dict dictionary
|
||||||
|
if movie_key == "locations":
|
||||||
|
if "locations" in movies_watched_list_2_keys_dict.keys():
|
||||||
|
# Iterate through the locations in the movie dictionary
|
||||||
|
for location in movie_value:
|
||||||
|
# If the location is in the movies_watched_list_2_keys_dict dictionary, return True
|
||||||
|
if location in movies_watched_list_2_keys_dict["locations"]:
|
||||||
|
return True
|
||||||
|
# If the key is not "locations", check if the movie_key is present in the movies_watched_list_2_keys_dict dictionary
|
||||||
|
else:
|
||||||
|
if movie_key in movies_watched_list_2_keys_dict.keys():
|
||||||
|
# If the movie_value is in the movies_watched_list_2_keys_dict dictionary, return True
|
||||||
|
if movie_value in movies_watched_list_2_keys_dict[movie_key]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# If the loop completes without finding a match, return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_episode_in_dict(episode, episode_watched_list_2_keys_dict):
|
||||||
|
# Iterate through the keys and values of the episode dictionary
|
||||||
|
for episode_key, episode_value in episode.items():
|
||||||
|
# If the key is "locations", check if the "locations" key is present in the episode_watched_list_2_keys_dict dictionary
|
||||||
|
if episode_key == "locations":
|
||||||
|
if "locations" in episode_watched_list_2_keys_dict.keys():
|
||||||
|
# Iterate through the locations in the episode dictionary
|
||||||
|
for location in episode_value:
|
||||||
|
# If the location is in the episode_watched_list_2_keys_dict dictionary, return True
|
||||||
|
if location in episode_watched_list_2_keys_dict["locations"]:
|
||||||
|
return True
|
||||||
|
# If the key is not "locations", check if the episode_key is present in the episode_watched_list_2_keys_dict dictionary
|
||||||
|
else:
|
||||||
|
if episode_key in episode_watched_list_2_keys_dict.keys():
|
||||||
|
# If the episode_value is in the episode_watched_list_2_keys_dict dictionary, return True
|
||||||
|
if episode_value in episode_watched_list_2_keys_dict[episode_key]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# If the loop completes without finding a match, return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def future_thread_executor(args: list, workers: int = -1):
|
def future_thread_executor(args: list, workers: int = -1):
|
||||||
futures_list = []
|
futures_list = []
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
if workers == -1:
|
if workers == -1:
|
||||||
workers = min(32, os.cpu_count() * 1.25)
|
workers = min(32, os.cpu_count() * 2)
|
||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=workers) as executor:
|
with ThreadPoolExecutor(max_workers=workers) as executor:
|
||||||
for arg in args:
|
for arg in args:
|
||||||
|
|
|
||||||
210
src/jellyfin.py
210
src/jellyfin.py
|
|
@ -73,7 +73,7 @@ class Jellyfin:
|
||||||
logger(f"Jellyfin: Get users failed {e}", 2)
|
logger(f"Jellyfin: Get users failed {e}", 2)
|
||||||
raise Exception(e)
|
raise Exception(e)
|
||||||
|
|
||||||
async def get_user_watched(
|
async def get_user_library_watched(
|
||||||
self, user_name, user_id, library_type, library_id, library_title
|
self, user_name, user_id, library_type, library_id, library_title
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
|
|
@ -85,8 +85,9 @@ class Jellyfin:
|
||||||
f"Jellyfin: Generating watched for {user_name} in library {library_title}",
|
f"Jellyfin: Generating watched for {user_name} in library {library_title}",
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
# Movies
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
|
# Movies
|
||||||
if library_type == "Movie":
|
if library_type == "Movie":
|
||||||
user_watched[user_name][library_title] = []
|
user_watched[user_name][library_title] = []
|
||||||
watched = await self.query(
|
watched = await self.query(
|
||||||
|
|
@ -95,16 +96,42 @@ class Jellyfin:
|
||||||
"get",
|
"get",
|
||||||
session,
|
session,
|
||||||
)
|
)
|
||||||
|
|
||||||
for movie in watched["Items"]:
|
for movie in watched["Items"]:
|
||||||
if movie["UserData"]["Played"] is True:
|
# Check if the movie has been played
|
||||||
movie_guids = {}
|
if (
|
||||||
movie_guids["title"] = movie["Name"]
|
movie["UserData"]["Played"] is True
|
||||||
|
and "MediaSources" in movie
|
||||||
|
and movie["MediaSources"] is not {}
|
||||||
|
):
|
||||||
|
logger(
|
||||||
|
f"Jellyfin: Adding {movie['Name']} to {user_name} watched list",
|
||||||
|
3,
|
||||||
|
)
|
||||||
if "ProviderIds" in movie:
|
if "ProviderIds" in movie:
|
||||||
# Lowercase movie["ProviderIds"] keys
|
logger(
|
||||||
movie_guids = {
|
f"Jellyfin: {movie['Name']} {movie['ProviderIds']} {movie['MediaSources']}",
|
||||||
k.lower(): v
|
3,
|
||||||
for k, v in movie["ProviderIds"].items()
|
)
|
||||||
}
|
else:
|
||||||
|
logger(
|
||||||
|
f"Jellyfin: {movie['Name']} {movie['MediaSources']['Path']}",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a dictionary for the movie with its title
|
||||||
|
movie_guids = {"title": movie["Name"]}
|
||||||
|
|
||||||
|
# If the movie has provider IDs, add them to the dictionary
|
||||||
|
if "ProviderIds" in movie:
|
||||||
|
movie_guids.update(
|
||||||
|
{
|
||||||
|
k.lower(): v
|
||||||
|
for k, v in movie["ProviderIds"].items()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# If the movie has media sources, add them to the dictionary
|
||||||
if "MediaSources" in movie:
|
if "MediaSources" in movie:
|
||||||
movie_guids["locations"] = tuple(
|
movie_guids["locations"] = tuple(
|
||||||
[
|
[
|
||||||
|
|
@ -112,45 +139,67 @@ class Jellyfin:
|
||||||
for x in movie["MediaSources"]
|
for x in movie["MediaSources"]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Append the movie dictionary to the list for the given user and library
|
||||||
user_watched[user_name][library_title].append(movie_guids)
|
user_watched[user_name][library_title].append(movie_guids)
|
||||||
|
logger(
|
||||||
|
f"Jellyfin: Added {movie_guids} to {user_name} watched list",
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
# TV Shows
|
# TV Shows
|
||||||
if library_type == "Series":
|
if library_type == "Series":
|
||||||
|
# Initialize an empty dictionary for the given user and library
|
||||||
user_watched[user_name][library_title] = {}
|
user_watched[user_name][library_title] = {}
|
||||||
|
|
||||||
|
# Retrieve a list of watched TV shows
|
||||||
watched_shows = await self.query(
|
watched_shows = await self.query(
|
||||||
f"/Users/{user_id}/Items"
|
f"/Users/{user_id}/Items"
|
||||||
+ f"?ParentId={library_id}&isPlaceHolder=false&Fields=ProviderIds,Path,RecursiveItemCount",
|
+ f"?ParentId={library_id}&isPlaceHolder=false&Fields=ProviderIds,Path,RecursiveItemCount",
|
||||||
"get",
|
"get",
|
||||||
session,
|
session,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Filter the list of shows to only include those that have been partially or fully watched
|
||||||
watched_shows_filtered = []
|
watched_shows_filtered = []
|
||||||
for show in watched_shows["Items"]:
|
for show in watched_shows["Items"]:
|
||||||
if "PlayedPercentage" in show["UserData"]:
|
if "PlayedPercentage" in show["UserData"]:
|
||||||
if show["UserData"]["PlayedPercentage"] > 0:
|
if show["UserData"]["PlayedPercentage"] > 0:
|
||||||
watched_shows_filtered.append(show)
|
watched_shows_filtered.append(show)
|
||||||
|
|
||||||
|
# Create a list of tasks to retrieve the seasons of each watched show
|
||||||
seasons_tasks = []
|
seasons_tasks = []
|
||||||
for show in watched_shows_filtered:
|
for show in watched_shows_filtered:
|
||||||
|
logger(
|
||||||
|
f"Jellyfin: Adding {show['Name']} to {user_name} watched list",
|
||||||
|
3,
|
||||||
|
)
|
||||||
show_guids = {
|
show_guids = {
|
||||||
k.lower(): v for k, v in show["ProviderIds"].items()
|
k.lower(): v for k, v in show["ProviderIds"].items()
|
||||||
}
|
}
|
||||||
show_guids["title"] = show["Name"]
|
show_guids["title"] = show["Name"]
|
||||||
show_guids["locations"] = tuple([show["Path"].split("/")[-1]])
|
show_guids["locations"] = tuple([show["Path"].split("/")[-1]])
|
||||||
show_guids = frozenset(show_guids.items())
|
show_guids = frozenset(show_guids.items())
|
||||||
identifiers = {"show_guids": show_guids, "show_id": show["Id"]}
|
show_identifiers = {
|
||||||
task = asyncio.ensure_future(
|
"show_guids": show_guids,
|
||||||
|
"show_id": show["Id"],
|
||||||
|
}
|
||||||
|
season_task = asyncio.ensure_future(
|
||||||
self.query(
|
self.query(
|
||||||
f"/Shows/{show['Id']}/Seasons"
|
f"/Shows/{show['Id']}/Seasons"
|
||||||
+ f"?userId={user_id}&isPlaceHolder=false&Fields=ProviderIds,RecursiveItemCount",
|
+ f"?userId={user_id}&isPlaceHolder=false&Fields=ProviderIds,RecursiveItemCount",
|
||||||
"get",
|
"get",
|
||||||
session,
|
session,
|
||||||
frozenset(identifiers.items()),
|
frozenset(show_identifiers.items()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
seasons_tasks.append(task)
|
seasons_tasks.append(season_task)
|
||||||
|
|
||||||
|
# Retrieve the seasons for each watched show
|
||||||
seasons_watched = await asyncio.gather(*seasons_tasks)
|
seasons_watched = await asyncio.gather(*seasons_tasks)
|
||||||
seasons_watched_filtered = []
|
|
||||||
|
|
||||||
|
# Filter the list of seasons to only include those that have been partially or fully watched
|
||||||
|
seasons_watched_filtered = []
|
||||||
for seasons in seasons_watched:
|
for seasons in seasons_watched:
|
||||||
seasons_watched_filtered_dict = {}
|
seasons_watched_filtered_dict = {}
|
||||||
seasons_watched_filtered_dict["Identifiers"] = seasons[
|
seasons_watched_filtered_dict["Identifiers"] = seasons[
|
||||||
|
|
@ -169,6 +218,7 @@ class Jellyfin:
|
||||||
seasons_watched_filtered_dict
|
seasons_watched_filtered_dict
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Create a list of tasks to retrieve the episodes of each watched season
|
||||||
episodes_tasks = []
|
episodes_tasks = []
|
||||||
for seasons in seasons_watched_filtered:
|
for seasons in seasons_watched_filtered:
|
||||||
if len(seasons["Items"]) > 0:
|
if len(seasons["Items"]) > 0:
|
||||||
|
|
@ -176,7 +226,7 @@ class Jellyfin:
|
||||||
season_identifiers = dict(seasons["Identifiers"])
|
season_identifiers = dict(seasons["Identifiers"])
|
||||||
season_identifiers["season_id"] = season["Id"]
|
season_identifiers["season_id"] = season["Id"]
|
||||||
season_identifiers["season_name"] = season["Name"]
|
season_identifiers["season_name"] = season["Name"]
|
||||||
task = asyncio.ensure_future(
|
episode_task = asyncio.ensure_future(
|
||||||
self.query(
|
self.query(
|
||||||
f"/Shows/{season_identifiers['show_id']}/Episodes"
|
f"/Shows/{season_identifiers['show_id']}/Episodes"
|
||||||
+ f"?seasonId={season['Id']}&userId={user_id}&isPlaceHolder=false&isPlayed=true&Fields=ProviderIds,MediaSources",
|
+ f"?seasonId={season['Id']}&userId={user_id}&isPlaceHolder=false&isPlayed=true&Fields=ProviderIds,MediaSources",
|
||||||
|
|
@ -185,60 +235,73 @@ class Jellyfin:
|
||||||
frozenset(season_identifiers.items()),
|
frozenset(season_identifiers.items()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
episodes_tasks.append(task)
|
episodes_tasks.append(episode_task)
|
||||||
|
|
||||||
|
# Retrieve the episodes for each watched season
|
||||||
watched_episodes = await asyncio.gather(*episodes_tasks)
|
watched_episodes = await asyncio.gather(*episodes_tasks)
|
||||||
for episodes in watched_episodes:
|
|
||||||
if len(episodes["Items"]) > 0:
|
|
||||||
for episode in episodes["Items"]:
|
|
||||||
if episode["UserData"]["Played"] is True:
|
|
||||||
if (
|
|
||||||
"ProviderIds" in episode
|
|
||||||
or "MediaSources" in episode
|
|
||||||
):
|
|
||||||
episode_identifiers = dict(
|
|
||||||
episodes["Identifiers"]
|
|
||||||
)
|
|
||||||
show_guids = episode_identifiers["show_guids"]
|
|
||||||
if (
|
|
||||||
show_guids
|
|
||||||
not in user_watched[user_name][
|
|
||||||
library_title
|
|
||||||
]
|
|
||||||
):
|
|
||||||
user_watched[user_name][library_title][
|
|
||||||
show_guids
|
|
||||||
] = {}
|
|
||||||
if (
|
|
||||||
episode_identifiers["season_name"]
|
|
||||||
not in user_watched[user_name][
|
|
||||||
library_title
|
|
||||||
][show_guids]
|
|
||||||
):
|
|
||||||
user_watched[user_name][library_title][
|
|
||||||
show_guids
|
|
||||||
][episode_identifiers["season_name"]] = []
|
|
||||||
|
|
||||||
episode_guids = {}
|
# Iterate through the watched episodes
|
||||||
if "ProviderIds" in episode:
|
for episodes in watched_episodes:
|
||||||
episode_guids = {
|
# If the season has any watched episodes
|
||||||
k.lower(): v
|
if len(episodes["Items"]) > 0:
|
||||||
for k, v in episode[
|
# Create a dictionary for the season with its identifier and episodes
|
||||||
"ProviderIds"
|
season_dict = {}
|
||||||
].items()
|
season_dict["Identifiers"] = dict(episodes["Identifiers"])
|
||||||
}
|
season_dict["Episodes"] = []
|
||||||
if "MediaSources" in episode:
|
for episode in episodes["Items"]:
|
||||||
episode_guids["locations"] = tuple(
|
if (
|
||||||
[
|
episode["UserData"]["Played"] is True
|
||||||
x["Path"].split("/")[-1]
|
and "MediaSources" in episode
|
||||||
for x in episode["MediaSources"]
|
and episode["MediaSources"] is not {}
|
||||||
]
|
):
|
||||||
)
|
# Create a dictionary for the episode with its provider IDs and media sources
|
||||||
user_watched[user_name][library_title][
|
episode_dict = {
|
||||||
show_guids
|
k.lower(): v
|
||||||
][episode_identifiers["season_name"]].append(
|
for k, v in episode["ProviderIds"].items()
|
||||||
episode_guids
|
}
|
||||||
)
|
episode_dict["title"] = episode["Name"]
|
||||||
|
episode_dict["locations"] = tuple(
|
||||||
|
[
|
||||||
|
x["Path"].split("/")[-1]
|
||||||
|
for x in episode["MediaSources"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
# Add the episode dictionary to the season's list of episodes
|
||||||
|
season_dict["Episodes"].append(episode_dict)
|
||||||
|
# Add the season dictionary to the show's list of seasons
|
||||||
|
if (
|
||||||
|
season_dict["Identifiers"]["show_guids"]
|
||||||
|
not in user_watched[user_name][library_title]
|
||||||
|
):
|
||||||
|
user_watched[user_name][library_title][
|
||||||
|
season_dict["Identifiers"]["show_guids"]
|
||||||
|
] = {}
|
||||||
|
|
||||||
|
if (
|
||||||
|
season_dict["Identifiers"]["season_name"]
|
||||||
|
not in user_watched[user_name][library_title][
|
||||||
|
season_dict["Identifiers"]["show_guids"]
|
||||||
|
]
|
||||||
|
):
|
||||||
|
user_watched[user_name][library_title][
|
||||||
|
season_dict["Identifiers"]["show_guids"]
|
||||||
|
][season_dict["Identifiers"]["season_name"]] = []
|
||||||
|
|
||||||
|
user_watched[user_name][library_title][
|
||||||
|
season_dict["Identifiers"]["show_guids"]
|
||||||
|
][season_dict["Identifiers"]["season_name"]] = season_dict[
|
||||||
|
"Episodes"
|
||||||
|
]
|
||||||
|
logger(
|
||||||
|
f"Jellyfin: Added {season_dict['Episodes']} to {user_name} {season_dict['Identifiers']['show_guids']} watched list",
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
|
||||||
|
logger(
|
||||||
|
f"Jellyfin: Got watched for {user_name} in library {library_title}", 1
|
||||||
|
)
|
||||||
|
if library_title in user_watched[user_name]:
|
||||||
|
logger(f"Jellyfin: {user_watched[user_name][library_title]}", 3)
|
||||||
|
|
||||||
return user_watched
|
return user_watched
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -315,7 +378,7 @@ class Jellyfin:
|
||||||
|
|
||||||
# Get watched for user
|
# Get watched for user
|
||||||
task = asyncio.ensure_future(
|
task = asyncio.ensure_future(
|
||||||
self.get_user_watched(
|
self.get_user_library_watched(
|
||||||
user_name, user_id, library_type, library_id, library_title
|
user_name, user_id, library_type, library_id, library_title
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -342,7 +405,7 @@ class Jellyfin:
|
||||||
|
|
||||||
for user_name, user_id in users.items():
|
for user_name, user_id in users.items():
|
||||||
watched.append(
|
watched.append(
|
||||||
await self.get_users_watched(
|
self.get_users_watched(
|
||||||
user_name,
|
user_name,
|
||||||
user_id,
|
user_id,
|
||||||
blacklist_library,
|
blacklist_library,
|
||||||
|
|
@ -353,6 +416,7 @@ class Jellyfin:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watched = await asyncio.gather(*watched, return_exceptions=True)
|
||||||
for user_watched in watched:
|
for user_watched in watched:
|
||||||
user_watched_temp = combine_watched_dicts(user_watched)
|
user_watched_temp = combine_watched_dicts(user_watched)
|
||||||
for user, user_watched_temp in user_watched_temp.items():
|
for user, user_watched_temp in user_watched_temp.items():
|
||||||
|
|
@ -534,12 +598,12 @@ class Jellyfin:
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Jellyfin: Skipping episode {jellyfin_episode['Name']} as it is not in mark list for {user_name}",
|
f"Jellyfin: Skipping episode {jellyfin_episode['Name']} as it is not in mark list for {user_name}",
|
||||||
1,
|
3,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Jellyfin: Skipping show {jellyfin_show['Name']} as it is not in mark list for {user_name}",
|
f"Jellyfin: Skipping show {jellyfin_show['Name']} as it is not in mark list for {user_name}",
|
||||||
1,
|
3,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
@ -618,13 +682,13 @@ class Jellyfin:
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Jellyfin: Library {library} or {library_other} not found in library list",
|
f"Jellyfin: Library {library} or {library_other} not found in library list",
|
||||||
2,
|
1,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Jellyfin: Library {library} not found in library list",
|
f"Jellyfin: Library {library} not found in library list",
|
||||||
2,
|
1,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
||||||
408
src/main.py
408
src/main.py
|
|
@ -1,4 +1,4 @@
|
||||||
import copy, os, traceback, json, asyncio
|
import os, traceback, json, asyncio
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from time import sleep, perf_counter
|
from time import sleep, perf_counter
|
||||||
|
|
||||||
|
|
@ -6,7 +6,8 @@ from src.functions import (
|
||||||
logger,
|
logger,
|
||||||
str_to_bool,
|
str_to_bool,
|
||||||
search_mapping,
|
search_mapping,
|
||||||
generate_library_guids_dict,
|
cleanup_watched,
|
||||||
|
setup_black_white_lists,
|
||||||
)
|
)
|
||||||
from src.plex import Plex
|
from src.plex import Plex
|
||||||
from src.jellyfin import Jellyfin
|
from src.jellyfin import Jellyfin
|
||||||
|
|
@ -14,306 +15,6 @@ from src.jellyfin import Jellyfin
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|
||||||
def cleanup_watched(
|
|
||||||
watched_list_1, watched_list_2, user_mapping=None, library_mapping=None
|
|
||||||
):
|
|
||||||
modified_watched_list_1 = copy.deepcopy(watched_list_1)
|
|
||||||
|
|
||||||
# remove entries from plex_watched that are in jellyfin_watched
|
|
||||||
for user_1 in watched_list_1:
|
|
||||||
user_other = None
|
|
||||||
if user_mapping:
|
|
||||||
user_other = search_mapping(user_mapping, user_1)
|
|
||||||
if user_1 in modified_watched_list_1:
|
|
||||||
if user_1 in watched_list_2:
|
|
||||||
user_2 = user_1
|
|
||||||
elif user_other in watched_list_2:
|
|
||||||
user_2 = user_other
|
|
||||||
else:
|
|
||||||
logger(f"User {user_1} and {user_other} not found in watched list 2", 1)
|
|
||||||
continue
|
|
||||||
|
|
||||||
for library_1 in watched_list_1[user_1]:
|
|
||||||
library_other = None
|
|
||||||
if library_mapping:
|
|
||||||
library_other = search_mapping(library_mapping, library_1)
|
|
||||||
if library_1 in modified_watched_list_1[user_1]:
|
|
||||||
if library_1 in watched_list_2[user_2]:
|
|
||||||
library_2 = library_1
|
|
||||||
elif library_other in watched_list_2[user_2]:
|
|
||||||
library_2 = library_other
|
|
||||||
else:
|
|
||||||
logger(
|
|
||||||
f"library {library_1} and {library_other} not found in watched list 2",
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
(
|
|
||||||
_,
|
|
||||||
episode_watched_list_2_keys_dict,
|
|
||||||
movies_watched_list_2_keys_dict,
|
|
||||||
) = generate_library_guids_dict(watched_list_2[user_2][library_2])
|
|
||||||
|
|
||||||
# Movies
|
|
||||||
if isinstance(watched_list_1[user_1][library_1], list):
|
|
||||||
for movie in watched_list_1[user_1][library_1]:
|
|
||||||
movie_found = False
|
|
||||||
for movie_key, movie_value in movie.items():
|
|
||||||
if movie_key == "locations":
|
|
||||||
if (
|
|
||||||
"locations"
|
|
||||||
in movies_watched_list_2_keys_dict.keys()
|
|
||||||
):
|
|
||||||
for location in movie_value:
|
|
||||||
if (
|
|
||||||
location
|
|
||||||
in movies_watched_list_2_keys_dict[
|
|
||||||
"locations"
|
|
||||||
]
|
|
||||||
):
|
|
||||||
movie_found = True
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if (
|
|
||||||
movie_key
|
|
||||||
in movies_watched_list_2_keys_dict.keys()
|
|
||||||
):
|
|
||||||
if (
|
|
||||||
movie_value
|
|
||||||
in movies_watched_list_2_keys_dict[
|
|
||||||
movie_key
|
|
||||||
]
|
|
||||||
):
|
|
||||||
movie_found = True
|
|
||||||
|
|
||||||
if movie_found:
|
|
||||||
logger(f"Removing {movie} from {library_1}", 3)
|
|
||||||
modified_watched_list_1[user_1][library_1].remove(
|
|
||||||
movie
|
|
||||||
)
|
|
||||||
break
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
for show_key_1 in watched_list_1[user_1][library_1].keys():
|
|
||||||
show_key_dict = dict(show_key_1)
|
|
||||||
for season in watched_list_1[user_1][library_1][show_key_1]:
|
|
||||||
for episode in watched_list_1[user_1][library_1][
|
|
||||||
show_key_1
|
|
||||||
][season]:
|
|
||||||
episode_found = False
|
|
||||||
for episode_key, episode_value in episode.items():
|
|
||||||
# If episode_key and episode_value are in episode_watched_list_2_keys_dict exactly, then remove from watch_list_1
|
|
||||||
if episode_key == "locations":
|
|
||||||
if (
|
|
||||||
"locations"
|
|
||||||
in episode_watched_list_2_keys_dict.keys()
|
|
||||||
):
|
|
||||||
for location in episode_value:
|
|
||||||
if (
|
|
||||||
location
|
|
||||||
in episode_watched_list_2_keys_dict[
|
|
||||||
"locations"
|
|
||||||
]
|
|
||||||
):
|
|
||||||
episode_found = True
|
|
||||||
break
|
|
||||||
|
|
||||||
else:
|
|
||||||
if (
|
|
||||||
episode_key
|
|
||||||
in episode_watched_list_2_keys_dict.keys()
|
|
||||||
):
|
|
||||||
if (
|
|
||||||
episode_value
|
|
||||||
in episode_watched_list_2_keys_dict[
|
|
||||||
episode_key
|
|
||||||
]
|
|
||||||
):
|
|
||||||
episode_found = True
|
|
||||||
|
|
||||||
if episode_found:
|
|
||||||
if (
|
|
||||||
episode
|
|
||||||
in modified_watched_list_1[user_1][
|
|
||||||
library_1
|
|
||||||
][show_key_1][season]
|
|
||||||
):
|
|
||||||
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 {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
|
|
||||||
if (
|
|
||||||
len(
|
|
||||||
modified_watched_list_1[user_1][library_1][
|
|
||||||
show_key_1
|
|
||||||
]
|
|
||||||
)
|
|
||||||
== 0
|
|
||||||
):
|
|
||||||
if (
|
|
||||||
show_key_1
|
|
||||||
in modified_watched_list_1[user_1][library_1]
|
|
||||||
):
|
|
||||||
logger(
|
|
||||||
f"Removing {show_key_dict['title']} from {library_1} because it is empty",
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
del modified_watched_list_1[user_1][library_1][
|
|
||||||
show_key_1
|
|
||||||
]
|
|
||||||
|
|
||||||
for user_1 in watched_list_1:
|
|
||||||
for library_1 in watched_list_1[user_1]:
|
|
||||||
if library_1 in modified_watched_list_1[user_1]:
|
|
||||||
# If library is empty then remove it
|
|
||||||
if len(modified_watched_list_1[user_1][library_1]) == 0:
|
|
||||||
logger(f"Removing {library_1} from {user_1} because it is empty", 1)
|
|
||||||
del modified_watched_list_1[user_1][library_1]
|
|
||||||
|
|
||||||
if user_1 in modified_watched_list_1:
|
|
||||||
# If user is empty delete user
|
|
||||||
if len(modified_watched_list_1[user_1]) == 0:
|
|
||||||
logger(f"Removing {user_1} from watched list 1 because it is empty", 1)
|
|
||||||
del modified_watched_list_1[user_1]
|
|
||||||
|
|
||||||
return modified_watched_list_1
|
|
||||||
|
|
||||||
|
|
||||||
def setup_black_white_lists(
|
|
||||||
blacklist_library: str,
|
|
||||||
whitelist_library: str,
|
|
||||||
blacklist_library_type: str,
|
|
||||||
whitelist_library_type: str,
|
|
||||||
blacklist_users: str,
|
|
||||||
whitelist_users: str,
|
|
||||||
library_mapping=None,
|
|
||||||
user_mapping=None,
|
|
||||||
):
|
|
||||||
if blacklist_library:
|
|
||||||
if len(blacklist_library) > 0:
|
|
||||||
blacklist_library = blacklist_library.split(",")
|
|
||||||
blacklist_library = [x.strip() for x in blacklist_library]
|
|
||||||
if library_mapping:
|
|
||||||
temp_library = []
|
|
||||||
for library in blacklist_library:
|
|
||||||
library_other = search_mapping(library_mapping, library)
|
|
||||||
if library_other:
|
|
||||||
temp_library.append(library_other)
|
|
||||||
|
|
||||||
blacklist_library = blacklist_library + temp_library
|
|
||||||
else:
|
|
||||||
blacklist_library = []
|
|
||||||
logger(f"Blacklist Library: {blacklist_library}", 1)
|
|
||||||
|
|
||||||
if whitelist_library:
|
|
||||||
if len(whitelist_library) > 0:
|
|
||||||
whitelist_library = whitelist_library.split(",")
|
|
||||||
whitelist_library = [x.strip() for x in whitelist_library]
|
|
||||||
if library_mapping:
|
|
||||||
temp_library = []
|
|
||||||
for library in whitelist_library:
|
|
||||||
library_other = search_mapping(library_mapping, library)
|
|
||||||
if library_other:
|
|
||||||
temp_library.append(library_other)
|
|
||||||
|
|
||||||
whitelist_library = whitelist_library + temp_library
|
|
||||||
else:
|
|
||||||
whitelist_library = []
|
|
||||||
logger(f"Whitelist Library: {whitelist_library}", 1)
|
|
||||||
|
|
||||||
if blacklist_library_type:
|
|
||||||
if len(blacklist_library_type) > 0:
|
|
||||||
blacklist_library_type = blacklist_library_type.split(",")
|
|
||||||
blacklist_library_type = [x.lower().strip() for x in blacklist_library_type]
|
|
||||||
else:
|
|
||||||
blacklist_library_type = []
|
|
||||||
logger(f"Blacklist Library Type: {blacklist_library_type}", 1)
|
|
||||||
|
|
||||||
if whitelist_library_type:
|
|
||||||
if len(whitelist_library_type) > 0:
|
|
||||||
whitelist_library_type = whitelist_library_type.split(",")
|
|
||||||
whitelist_library_type = [x.lower().strip() for x in whitelist_library_type]
|
|
||||||
else:
|
|
||||||
whitelist_library_type = []
|
|
||||||
logger(f"Whitelist Library Type: {whitelist_library_type}", 1)
|
|
||||||
|
|
||||||
if blacklist_users:
|
|
||||||
if len(blacklist_users) > 0:
|
|
||||||
blacklist_users = blacklist_users.split(",")
|
|
||||||
blacklist_users = [x.lower().strip() for x in blacklist_users]
|
|
||||||
if user_mapping:
|
|
||||||
temp_users = []
|
|
||||||
for user in blacklist_users:
|
|
||||||
user_other = search_mapping(user_mapping, user)
|
|
||||||
if user_other:
|
|
||||||
temp_users.append(user_other)
|
|
||||||
|
|
||||||
blacklist_users = blacklist_users + temp_users
|
|
||||||
else:
|
|
||||||
blacklist_users = []
|
|
||||||
logger(f"Blacklist Users: {blacklist_users}", 1)
|
|
||||||
|
|
||||||
if whitelist_users:
|
|
||||||
if len(whitelist_users) > 0:
|
|
||||||
whitelist_users = whitelist_users.split(",")
|
|
||||||
whitelist_users = [x.lower().strip() for x in whitelist_users]
|
|
||||||
if user_mapping:
|
|
||||||
temp_users = []
|
|
||||||
for user in whitelist_users:
|
|
||||||
user_other = search_mapping(user_mapping, user)
|
|
||||||
if user_other:
|
|
||||||
temp_users.append(user_other)
|
|
||||||
|
|
||||||
whitelist_users = whitelist_users + temp_users
|
|
||||||
else:
|
|
||||||
whitelist_users = []
|
|
||||||
else:
|
|
||||||
whitelist_users = []
|
|
||||||
logger(f"Whitelist Users: {whitelist_users}", 1)
|
|
||||||
|
|
||||||
return (
|
|
||||||
blacklist_library,
|
|
||||||
whitelist_library,
|
|
||||||
blacklist_library_type,
|
|
||||||
whitelist_library_type,
|
|
||||||
blacklist_users,
|
|
||||||
whitelist_users,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_users(
|
def setup_users(
|
||||||
server_1, server_2, blacklist_users, whitelist_users, user_mapping=None
|
server_1, server_2, blacklist_users, whitelist_users, user_mapping=None
|
||||||
):
|
):
|
||||||
|
|
@ -323,8 +24,8 @@ def setup_users(
|
||||||
server_1_connection = server_1[1]
|
server_1_connection = server_1[1]
|
||||||
server_2_type = server_2[0]
|
server_2_type = server_2[0]
|
||||||
server_2_connection = server_2[1]
|
server_2_connection = server_2[1]
|
||||||
print(f"Server 1: {server_1_type} {server_1_connection}")
|
logger(f"Server 1: {server_1_type} {server_1_connection}", 0)
|
||||||
print(f"Server 2: {server_2_type} {server_2_connection}")
|
logger(f"Server 2: {server_2_type} {server_2_connection}", 0)
|
||||||
|
|
||||||
server_1_users = []
|
server_1_users = []
|
||||||
if server_1_type == "plex":
|
if server_1_type == "plex":
|
||||||
|
|
@ -500,16 +201,69 @@ def generate_server_connections():
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, baseurl in enumerate(jellyfin_baseurl):
|
for i, baseurl in enumerate(jellyfin_baseurl):
|
||||||
|
baseurl = baseurl.strip()
|
||||||
|
if baseurl[-1] == "/":
|
||||||
|
baseurl = baseurl[:-1]
|
||||||
servers.append(
|
servers.append(
|
||||||
(
|
(
|
||||||
"jellyfin",
|
"jellyfin",
|
||||||
Jellyfin(baseurl=baseurl.strip(), token=jellyfin_token[i].strip()),
|
Jellyfin(baseurl=baseurl, token=jellyfin_token[i].strip()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return servers
|
return servers
|
||||||
|
|
||||||
|
|
||||||
|
def get_server_watched(
|
||||||
|
server_connection: list,
|
||||||
|
users: dict,
|
||||||
|
blacklist_library: list,
|
||||||
|
whitelist_library: list,
|
||||||
|
blacklist_library_type: list,
|
||||||
|
whitelist_library_type: list,
|
||||||
|
library_mapping: dict,
|
||||||
|
):
|
||||||
|
if server_connection[0] == "plex":
|
||||||
|
return server_connection[1].get_watched(
|
||||||
|
users,
|
||||||
|
blacklist_library,
|
||||||
|
whitelist_library,
|
||||||
|
blacklist_library_type,
|
||||||
|
whitelist_library_type,
|
||||||
|
library_mapping,
|
||||||
|
)
|
||||||
|
elif server_connection[0] == "jellyfin":
|
||||||
|
return asyncio.run(
|
||||||
|
server_connection[1].get_watched(
|
||||||
|
users,
|
||||||
|
blacklist_library,
|
||||||
|
whitelist_library,
|
||||||
|
blacklist_library_type,
|
||||||
|
whitelist_library_type,
|
||||||
|
library_mapping,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def update_server_watched(
|
||||||
|
server_connection: list,
|
||||||
|
server_watched_filtered: dict,
|
||||||
|
user_mapping: dict,
|
||||||
|
library_mapping: dict,
|
||||||
|
dryrun: bool,
|
||||||
|
):
|
||||||
|
if server_connection[0] == "plex":
|
||||||
|
server_connection[1].update_watched(
|
||||||
|
server_watched_filtered, user_mapping, library_mapping, dryrun
|
||||||
|
)
|
||||||
|
elif server_connection[0] == "jellyfin":
|
||||||
|
asyncio.run(
|
||||||
|
server_connection[1].update_watched(
|
||||||
|
server_watched_filtered, user_mapping, library_mapping, dryrun
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main_loop():
|
def main_loop():
|
||||||
logfile = os.getenv("LOGFILE", "log.log")
|
logfile = os.getenv("LOGFILE", "log.log")
|
||||||
# Delete logfile if it exists
|
# Delete logfile if it exists
|
||||||
|
|
@ -567,10 +321,6 @@ def main_loop():
|
||||||
|
|
||||||
# Start server_2 at the next server in the list
|
# Start server_2 at the next server in the list
|
||||||
for server_2 in servers[servers.index(server_1) + 1 :]:
|
for server_2 in servers[servers.index(server_1) + 1 :]:
|
||||||
|
|
||||||
server_1_connection = server_1[1]
|
|
||||||
server_2_connection = server_2[1]
|
|
||||||
|
|
||||||
# Create users list
|
# Create users list
|
||||||
logger("Creating users list", 1)
|
logger("Creating users list", 1)
|
||||||
server_1_users, server_2_users = setup_users(
|
server_1_users, server_2_users = setup_users(
|
||||||
|
|
@ -578,7 +328,8 @@ def main_loop():
|
||||||
)
|
)
|
||||||
|
|
||||||
logger("Creating watched lists", 1)
|
logger("Creating watched lists", 1)
|
||||||
server_1_watched = server_1_connection.get_watched(
|
server_1_watched = get_server_watched(
|
||||||
|
server_1,
|
||||||
server_1_users,
|
server_1_users,
|
||||||
blacklist_library,
|
blacklist_library,
|
||||||
whitelist_library,
|
whitelist_library,
|
||||||
|
|
@ -587,15 +338,14 @@ def main_loop():
|
||||||
library_mapping,
|
library_mapping,
|
||||||
)
|
)
|
||||||
logger("Finished creating watched list server 1", 1)
|
logger("Finished creating watched list server 1", 1)
|
||||||
server_2_watched = asyncio.run(
|
server_2_watched = get_server_watched(
|
||||||
server_2_connection.get_watched(
|
server_2,
|
||||||
server_2_users,
|
server_2_users,
|
||||||
blacklist_library,
|
blacklist_library,
|
||||||
whitelist_library,
|
whitelist_library,
|
||||||
blacklist_library_type,
|
blacklist_library_type,
|
||||||
whitelist_library_type,
|
whitelist_library_type,
|
||||||
library_mapping,
|
library_mapping,
|
||||||
)
|
|
||||||
)
|
)
|
||||||
logger("Finished creating watched list server 2", 1)
|
logger("Finished creating watched list server 2", 1)
|
||||||
logger(f"Server 1 watched: {server_1_watched}", 3)
|
logger(f"Server 1 watched: {server_1_watched}", 3)
|
||||||
|
|
@ -620,13 +370,20 @@ def main_loop():
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
|
||||||
server_1_connection.update_watched(
|
update_server_watched(
|
||||||
server_2_watched_filtered, user_mapping, library_mapping, dryrun
|
server_1,
|
||||||
|
server_2_watched_filtered,
|
||||||
|
user_mapping,
|
||||||
|
library_mapping,
|
||||||
|
dryrun,
|
||||||
)
|
)
|
||||||
asyncio.run(
|
|
||||||
server_2_connection.update_watched(
|
update_server_watched(
|
||||||
server_1_watched_filtered, user_mapping, library_mapping, dryrun
|
server_2,
|
||||||
)
|
server_1_watched_filtered,
|
||||||
|
user_mapping,
|
||||||
|
library_mapping,
|
||||||
|
dryrun,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -654,6 +411,7 @@ def main():
|
||||||
logger(error, log_type=2)
|
logger(error, log_type=2)
|
||||||
|
|
||||||
logger(traceback.format_exc(), 2)
|
logger(traceback.format_exc(), 2)
|
||||||
|
|
||||||
logger(f"Retrying in {sleep_duration}", log_type=0)
|
logger(f"Retrying in {sleep_duration}", log_type=0)
|
||||||
sleep(sleep_duration)
|
sleep(sleep_duration)
|
||||||
|
|
||||||
|
|
|
||||||
112
src/plex.py
112
src/plex.py
|
|
@ -15,13 +15,16 @@ from src.functions import (
|
||||||
# Bypass hostname validation for ssl. Taken from https://github.com/pkkid/python-plexapi/issues/143#issuecomment-775485186
|
# Bypass hostname validation for ssl. Taken from https://github.com/pkkid/python-plexapi/issues/143#issuecomment-775485186
|
||||||
class HostNameIgnoringAdapter(requests.adapters.HTTPAdapter):
|
class HostNameIgnoringAdapter(requests.adapters.HTTPAdapter):
|
||||||
def init_poolmanager(self, connections, maxsize, block=..., **pool_kwargs):
|
def init_poolmanager(self, connections, maxsize, block=..., **pool_kwargs):
|
||||||
self.poolmanager = PoolManager(num_pools=connections,
|
self.poolmanager = PoolManager(
|
||||||
maxsize=maxsize,
|
num_pools=connections,
|
||||||
block=block,
|
maxsize=maxsize,
|
||||||
assert_hostname=False,
|
block=block,
|
||||||
**pool_kwargs)
|
assert_hostname=False,
|
||||||
|
**pool_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def get_user_watched(user, user_plex, library):
|
|
||||||
|
def get_user_library_watched(user, user_plex, library):
|
||||||
try:
|
try:
|
||||||
user_name = user.title.lower()
|
user_name = user.title.lower()
|
||||||
user_watched = {}
|
user_watched = {}
|
||||||
|
|
@ -32,15 +35,20 @@ def get_user_watched(user, user_plex, library):
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
library_videos = user_plex.library.section(library.title)
|
||||||
|
|
||||||
if library.type == "movie":
|
if library.type == "movie":
|
||||||
user_watched[user_name][library.title] = []
|
user_watched[user_name][library.title] = []
|
||||||
|
|
||||||
library_videos = user_plex.library.section(library.title)
|
|
||||||
for video in library_videos.search(unwatched=False):
|
for video in library_videos.search(unwatched=False):
|
||||||
|
logger(f"Plex: Adding {video.title} to {user_name} watched list", 3)
|
||||||
|
logger(f"Plex: {video.title} {video.guids} {video.locations}", 3)
|
||||||
|
|
||||||
movie_guids = {}
|
movie_guids = {}
|
||||||
for guid in video.guids:
|
for guid in video.guids:
|
||||||
guid_source = re.search(r"(.*)://", guid.id).group(1).lower()
|
# Extract source and id from guid.id
|
||||||
guid_id = re.search(r"://(.*)", guid.id).group(1)
|
m = re.match(r"(.*)://(.*)", guid.id)
|
||||||
|
guid_source, guid_id = m.group(1).lower(), m.group(2)
|
||||||
movie_guids[guid_source] = guid_id
|
movie_guids[guid_source] = guid_id
|
||||||
|
|
||||||
movie_guids["title"] = video.title
|
movie_guids["title"] = video.title
|
||||||
|
|
@ -49,19 +57,18 @@ def get_user_watched(user, user_plex, library):
|
||||||
)
|
)
|
||||||
|
|
||||||
user_watched[user_name][library.title].append(movie_guids)
|
user_watched[user_name][library.title].append(movie_guids)
|
||||||
|
logger(f"Plex: Added {movie_guids} to {user_name} watched list", 3)
|
||||||
|
|
||||||
elif library.type == "show":
|
elif library.type == "show":
|
||||||
user_watched[user_name][library.title] = {}
|
user_watched[user_name][library.title] = {}
|
||||||
|
|
||||||
library_videos = user_plex.library.section(library.title)
|
|
||||||
for show in 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 = {}
|
show_guids = {}
|
||||||
for show_guid in show.guids:
|
for show_guid in show.guids:
|
||||||
# Extract after :// from guid.id
|
# Extract source and id from guid.id
|
||||||
show_guid_source = (
|
m = re.match(r"(.*)://(.*)", show_guid.id)
|
||||||
re.search(r"(.*)://", show_guid.id).group(1).lower()
|
show_guid_source, show_guid_id = m.group(1).lower(), m.group(2)
|
||||||
)
|
|
||||||
show_guid_id = re.search(r"://(.*)", show_guid.id).group(1)
|
|
||||||
show_guids[show_guid_source] = show_guid_id
|
show_guids[show_guid_source] = show_guid_id
|
||||||
|
|
||||||
show_guids["title"] = show.title
|
show_guids["title"] = show.title
|
||||||
|
|
@ -70,38 +77,38 @@ def get_user_watched(user, user_plex, library):
|
||||||
)
|
)
|
||||||
show_guids = frozenset(show_guids.items())
|
show_guids = frozenset(show_guids.items())
|
||||||
|
|
||||||
for season in show.seasons():
|
# Get all watched episodes for show
|
||||||
episode_guids = []
|
episode_guids = {}
|
||||||
for episode in season.episodes():
|
for episode in show.watched():
|
||||||
if episode.viewCount > 0:
|
if episode.viewCount > 0:
|
||||||
episode_guids_temp = {}
|
episode_guids_temp = {}
|
||||||
for guid in episode.guids:
|
for guid in episode.guids:
|
||||||
# Extract after :// from guid.id
|
# Extract after :// from guid.id
|
||||||
guid_source = (
|
m = re.match(r"(.*)://(.*)", guid.id)
|
||||||
re.search(r"(.*)://", guid.id).group(1).lower()
|
guid_source, guid_id = m.group(1).lower(), m.group(2)
|
||||||
)
|
episode_guids_temp[guid_source] = guid_id
|
||||||
guid_id = re.search(r"://(.*)", guid.id).group(1)
|
|
||||||
episode_guids_temp[guid_source] = guid_id
|
|
||||||
|
|
||||||
episode_guids_temp["locations"] = tuple(
|
episode_guids_temp["locations"] = tuple(
|
||||||
[x.split("/")[-1] for x in episode.locations]
|
[x.split("/")[-1] for x in episode.locations]
|
||||||
)
|
)
|
||||||
episode_guids.append(episode_guids_temp)
|
if episode.parentTitle not in episode_guids:
|
||||||
|
episode_guids[episode.parentTitle] = []
|
||||||
|
episode_guids[episode.parentTitle].append(episode_guids_temp)
|
||||||
|
|
||||||
if episode_guids:
|
if episode_guids:
|
||||||
# append show, season, episode
|
# append show, season, episode
|
||||||
if show_guids not in user_watched[user_name][library.title]:
|
if show_guids not in user_watched[user_name][library.title]:
|
||||||
user_watched[user_name][library.title][show_guids] = {}
|
user_watched[user_name][library.title][show_guids] = {}
|
||||||
if (
|
|
||||||
season.title
|
user_watched[user_name][library.title][show_guids] = episode_guids
|
||||||
not in user_watched[user_name][library.title][show_guids]
|
logger(
|
||||||
):
|
f"Plex: Added {episode_guids} to {user_name} {show_guids} watched list",
|
||||||
user_watched[user_name][library.title][show_guids][
|
3,
|
||||||
season.title
|
)
|
||||||
] = {}
|
|
||||||
user_watched[user_name][library.title][show_guids][
|
logger(f"Plex: Got watched for {user_name} in library {library.title}", 1)
|
||||||
season.title
|
if library.title in user_watched[user_name]:
|
||||||
] = episode_guids
|
logger(f"Plex: {user_watched[user_name][library.title]}", 3)
|
||||||
|
|
||||||
return user_watched
|
return user_watched
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -223,12 +230,12 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Plex: Skipping episode {episode_search.title} as it is not in mark list for {user.title}",
|
f"Plex: Skipping episode {episode_search.title} as it is not in mark list for {user.title}",
|
||||||
1,
|
3,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Plex: Skipping show {show_search.title} as it is not in mark list for {user.title}",
|
f"Plex: Skipping show {show_search.title} as it is not in mark list for {user.title}",
|
||||||
1,
|
3,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not videos_movies_ids and not videos_shows_ids and not videos_episodes_ids:
|
if not videos_movies_ids and not videos_shows_ids and not videos_episodes_ids:
|
||||||
|
|
@ -324,7 +331,9 @@ class Plex:
|
||||||
user_plex = self.plex
|
user_plex = self.plex
|
||||||
else:
|
else:
|
||||||
user_plex = self.login(
|
user_plex = self.login(
|
||||||
self.plex._baseurl, user.get_token(self.plex.machineIdentifier), self.ssl_bypass
|
self.plex._baseurl,
|
||||||
|
user.get_token(self.plex.machineIdentifier),
|
||||||
|
self.ssl_bypass,
|
||||||
)
|
)
|
||||||
|
|
||||||
libraries = user_plex.library.sections()
|
libraries = user_plex.library.sections()
|
||||||
|
|
@ -349,7 +358,7 @@ class Plex:
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
args.append([get_user_watched, user, user_plex, library])
|
args.append([get_user_library_watched, user, user_plex, library])
|
||||||
|
|
||||||
for user_watched in future_thread_executor(args):
|
for user_watched in future_thread_executor(args):
|
||||||
for user, user_watched_temp in user_watched.items():
|
for user, user_watched_temp in user_watched.items():
|
||||||
|
|
@ -415,12 +424,13 @@ class Plex:
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Plex: Library {library} or {library_other} not found in library list",
|
f"Plex: Library {library} or {library_other} not found in library list",
|
||||||
2,
|
1,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
logger(
|
logger(
|
||||||
f"Plex: Library {library} not found in library list", 2
|
f"Plex: Library {library} not found in library list",
|
||||||
|
1,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,78 +1,78 @@
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# getting the name of the directory
|
# getting the name of the directory
|
||||||
# where the this file is present.
|
# where the this file is present.
|
||||||
current = os.path.dirname(os.path.realpath(__file__))
|
current = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
# Getting the parent directory name
|
# Getting the parent directory name
|
||||||
# where the current directory is present.
|
# where the current directory is present.
|
||||||
parent = os.path.dirname(current)
|
parent = os.path.dirname(current)
|
||||||
|
|
||||||
# adding the parent directory to
|
# adding the parent directory to
|
||||||
# the sys.path.
|
# the sys.path.
|
||||||
sys.path.append(parent)
|
sys.path.append(parent)
|
||||||
|
|
||||||
from src.main import setup_black_white_lists
|
from src.main import setup_black_white_lists
|
||||||
|
|
||||||
|
|
||||||
def test_setup_black_white_lists():
|
def test_setup_black_white_lists():
|
||||||
# Simple
|
# Simple
|
||||||
blacklist_library = "library1, library2"
|
blacklist_library = "library1, library2"
|
||||||
whitelist_library = "library1, library2"
|
whitelist_library = "library1, library2"
|
||||||
blacklist_library_type = "library_type1, library_type2"
|
blacklist_library_type = "library_type1, library_type2"
|
||||||
whitelist_library_type = "library_type1, library_type2"
|
whitelist_library_type = "library_type1, library_type2"
|
||||||
blacklist_users = "user1, user2"
|
blacklist_users = "user1, user2"
|
||||||
whitelist_users = "user1, user2"
|
whitelist_users = "user1, user2"
|
||||||
|
|
||||||
(
|
(
|
||||||
results_blacklist_library,
|
results_blacklist_library,
|
||||||
return_whitelist_library,
|
return_whitelist_library,
|
||||||
return_blacklist_library_type,
|
return_blacklist_library_type,
|
||||||
return_whitelist_library_type,
|
return_whitelist_library_type,
|
||||||
return_blacklist_users,
|
return_blacklist_users,
|
||||||
return_whitelist_users,
|
return_whitelist_users,
|
||||||
) = setup_black_white_lists(
|
) = setup_black_white_lists(
|
||||||
blacklist_library,
|
blacklist_library,
|
||||||
whitelist_library,
|
whitelist_library,
|
||||||
blacklist_library_type,
|
blacklist_library_type,
|
||||||
whitelist_library_type,
|
whitelist_library_type,
|
||||||
blacklist_users,
|
blacklist_users,
|
||||||
whitelist_users,
|
whitelist_users,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert results_blacklist_library == ["library1", "library2"]
|
assert results_blacklist_library == ["library1", "library2"]
|
||||||
assert return_whitelist_library == ["library1", "library2"]
|
assert return_whitelist_library == ["library1", "library2"]
|
||||||
assert return_blacklist_library_type == ["library_type1", "library_type2"]
|
assert return_blacklist_library_type == ["library_type1", "library_type2"]
|
||||||
assert return_whitelist_library_type == ["library_type1", "library_type2"]
|
assert return_whitelist_library_type == ["library_type1", "library_type2"]
|
||||||
assert return_blacklist_users == ["user1", "user2"]
|
assert return_blacklist_users == ["user1", "user2"]
|
||||||
assert return_whitelist_users == ["user1", "user2"]
|
assert return_whitelist_users == ["user1", "user2"]
|
||||||
|
|
||||||
# Library Mapping and user mapping
|
# Library Mapping and user mapping
|
||||||
library_mapping = {"library1": "library3"}
|
library_mapping = {"library1": "library3"}
|
||||||
user_mapping = {"user1": "user3"}
|
user_mapping = {"user1": "user3"}
|
||||||
|
|
||||||
(
|
(
|
||||||
results_blacklist_library,
|
results_blacklist_library,
|
||||||
return_whitelist_library,
|
return_whitelist_library,
|
||||||
return_blacklist_library_type,
|
return_blacklist_library_type,
|
||||||
return_whitelist_library_type,
|
return_whitelist_library_type,
|
||||||
return_blacklist_users,
|
return_blacklist_users,
|
||||||
return_whitelist_users,
|
return_whitelist_users,
|
||||||
) = setup_black_white_lists(
|
) = setup_black_white_lists(
|
||||||
blacklist_library,
|
blacklist_library,
|
||||||
whitelist_library,
|
whitelist_library,
|
||||||
blacklist_library_type,
|
blacklist_library_type,
|
||||||
whitelist_library_type,
|
whitelist_library_type,
|
||||||
blacklist_users,
|
blacklist_users,
|
||||||
whitelist_users,
|
whitelist_users,
|
||||||
library_mapping,
|
library_mapping,
|
||||||
user_mapping,
|
user_mapping,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert results_blacklist_library == ["library1", "library2", "library3"]
|
assert results_blacklist_library == ["library1", "library2", "library3"]
|
||||||
assert return_whitelist_library == ["library1", "library2", "library3"]
|
assert return_whitelist_library == ["library1", "library2", "library3"]
|
||||||
assert return_blacklist_library_type == ["library_type1", "library_type2"]
|
assert return_blacklist_library_type == ["library_type1", "library_type2"]
|
||||||
assert return_whitelist_library_type == ["library_type1", "library_type2"]
|
assert return_whitelist_library_type == ["library_type1", "library_type2"]
|
||||||
assert return_blacklist_users == ["user1", "user2", "user3"]
|
assert return_blacklist_users == ["user1", "user2", "user3"]
|
||||||
assert return_whitelist_users == ["user1", "user2", "user3"]
|
assert return_whitelist_users == ["user1", "user2", "user3"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue