Fix server 2 always running async runner. Speedup plex get watched
parent
251937431b
commit
d0746cec5a
|
|
@ -178,28 +178,6 @@ def combine_watched_dicts(dicts: list):
|
||||||
return combined_dict
|
return combined_dict
|
||||||
|
|
||||||
|
|
||||||
def future_thread_executor(args: list, workers: int = -1):
|
|
||||||
futures_list = []
|
|
||||||
results = []
|
|
||||||
|
|
||||||
if workers == -1:
|
|
||||||
workers = min(32, os.cpu_count() * 1.25)
|
|
||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=workers) as executor:
|
|
||||||
for arg in args:
|
|
||||||
# * arg unpacks the list into actual arguments
|
|
||||||
futures_list.append(executor.submit(*arg))
|
|
||||||
|
|
||||||
for future in futures_list:
|
|
||||||
try:
|
|
||||||
result = future.result()
|
|
||||||
results.append(result)
|
|
||||||
except Exception as e:
|
|
||||||
raise Exception(e)
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup_watched(
|
def cleanup_watched(
|
||||||
watched_list_1, watched_list_2, user_mapping=None, library_mapping=None
|
watched_list_1, watched_list_2, user_mapping=None, library_mapping=None
|
||||||
):
|
):
|
||||||
|
|
@ -327,3 +305,24 @@ def is_episode_in_dict(episode, episode_watched_list_2_keys_dict):
|
||||||
|
|
||||||
# If the loop completes without finding a match, return False
|
# If the loop completes without finding a match, return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def future_thread_executor(args: list, workers: int = -1):
|
||||||
|
futures_list = []
|
||||||
|
results = []
|
||||||
|
|
||||||
|
if workers == -1:
|
||||||
|
workers = min(32, os.cpu_count() * 2)
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=workers) as executor:
|
||||||
|
for arg in args:
|
||||||
|
# * arg unpacks the list into actual arguments
|
||||||
|
futures_list.append(executor.submit(*arg))
|
||||||
|
|
||||||
|
for future in futures_list:
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
results.append(result)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(e)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,7 @@ class Jellyfin:
|
||||||
episode_guids
|
episode_guids
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger(f"Jellyfin: Got watched for {user_name} in library {library_title}")
|
||||||
return user_watched
|
return user_watched
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger(
|
logger(
|
||||||
|
|
@ -342,7 +343,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 +354,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 +536,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 +620,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
|
||||||
|
|
||||||
|
|
|
||||||
46
src/main.py
46
src/main.py
|
|
@ -310,6 +310,32 @@ def generate_server_connections():
|
||||||
|
|
||||||
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")
|
||||||
|
|
@ -379,7 +405,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,
|
||||||
|
|
@ -388,8 +415,8 @@ 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,
|
||||||
|
|
@ -397,7 +424,6 @@ def main_loop():
|
||||||
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)
|
||||||
logger(f"Server 2 watched: {server_2_watched}", 3)
|
logger(f"Server 2 watched: {server_2_watched}", 3)
|
||||||
|
|
@ -421,13 +447,12 @@ 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(
|
|
||||||
server_1_watched_filtered, user_mapping, library_mapping, dryrun
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
update_server_watched(
|
||||||
|
server_2, server_1_watched_filtered, user_mapping, library_mapping, dryrun
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -455,6 +480,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)
|
||||||
|
|
||||||
|
|
|
||||||
49
src/plex.py
49
src/plex.py
|
|
@ -54,14 +54,13 @@ def get_user_watched(user, user_plex, library):
|
||||||
user_watched[user_name][library.title] = {}
|
user_watched[user_name][library.title] = {}
|
||||||
|
|
||||||
library_videos = user_plex.library.section(library.title)
|
library_videos = user_plex.library.section(library.title)
|
||||||
for show in library_videos.search(unwatched=False):
|
shows = library_videos.search(unwatched=False)
|
||||||
|
for show in shows:
|
||||||
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,39 +69,32 @@ 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)
|
||||||
)
|
|
||||||
guid_id = re.search(r"://(.*)", guid.id).group(1)
|
|
||||||
episode_guids_temp[guid_source] = guid_id
|
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
|
|
||||||
not in user_watched[user_name][library.title][show_guids]
|
|
||||||
):
|
|
||||||
user_watched[user_name][library.title][show_guids][
|
|
||||||
season.title
|
|
||||||
] = {}
|
|
||||||
user_watched[user_name][library.title][show_guids][
|
|
||||||
season.title
|
|
||||||
] = episode_guids
|
|
||||||
|
|
||||||
|
user_watched[user_name][library.title][show_guids] = episode_guids
|
||||||
|
|
||||||
|
logger(f"Plex: Got watched for {user_name} in library {library.title}", 0)
|
||||||
return user_watched
|
return user_watched
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger(
|
logger(
|
||||||
|
|
@ -223,12 +215,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:
|
||||||
|
|
@ -415,12 +407,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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue