259 lines
9.0 KiB
Python
259 lines
9.0 KiB
Python
import os, traceback, json
|
|
from dotenv import load_dotenv
|
|
from time import sleep, perf_counter
|
|
|
|
from src.library import setup_libraries
|
|
from src.functions import (
|
|
logger,
|
|
str_to_bool,
|
|
)
|
|
from src.users import setup_users
|
|
from src.watched import (
|
|
cleanup_watched,
|
|
)
|
|
from src.black_white import setup_black_white_lists
|
|
from src.connection import generate_server_connections
|
|
|
|
load_dotenv(override=True)
|
|
|
|
|
|
def should_sync_server(server_1_type, server_2_type):
|
|
sync_from_plex_to_jellyfin = str_to_bool(
|
|
os.getenv("SYNC_FROM_PLEX_TO_JELLYFIN", "True")
|
|
)
|
|
sync_from_plex_to_plex = str_to_bool(os.getenv("SYNC_FROM_PLEX_TO_PLEX", "True"))
|
|
sync_from_plex_to_emby = str_to_bool(os.getenv("SYNC_FROM_PLEX_TO_EMBY", "True"))
|
|
|
|
sync_from_jelly_to_plex = str_to_bool(
|
|
os.getenv("SYNC_FROM_JELLYFIN_TO_PLEX", "True")
|
|
)
|
|
sync_from_jelly_to_jellyfin = str_to_bool(
|
|
os.getenv("SYNC_FROM_JELLYFIN_TO_JELLYFIN", "True")
|
|
)
|
|
sync_from_jelly_to_emby = str_to_bool(
|
|
os.getenv("SYNC_FROM_JELLYFIN_TO_EMBY", "True")
|
|
)
|
|
|
|
sync_from_emby_to_plex = str_to_bool(os.getenv("SYNC_FROM_EMBY_TO_PLEX", "True"))
|
|
sync_from_emby_to_jellyfin = str_to_bool(
|
|
os.getenv("SYNC_FROM_EMBY_TO_JELLYFIN", "True")
|
|
)
|
|
sync_from_emby_to_emby = str_to_bool(os.getenv("SYNC_FROM_EMBY_TO_EMBY", "True"))
|
|
|
|
if server_1_type == "plex":
|
|
if server_2_type == "jellyfin" and not sync_from_plex_to_jellyfin:
|
|
logger("Sync from plex -> jellyfin is disabled", 1)
|
|
return False
|
|
|
|
if server_2_type == "emby" and not sync_from_plex_to_emby:
|
|
logger("Sync from plex -> emby is disabled", 1)
|
|
return False
|
|
|
|
if server_2_type == "plex" and not sync_from_plex_to_plex:
|
|
logger("Sync from plex -> plex is disabled", 1)
|
|
return False
|
|
|
|
if server_1_type == "jellyfin":
|
|
if server_2_type == "plex" and not sync_from_jelly_to_plex:
|
|
logger("Sync from jellyfin -> plex is disabled", 1)
|
|
return False
|
|
|
|
if server_2_type == "jellyfin" and not sync_from_jelly_to_jellyfin:
|
|
logger("Sync from jellyfin -> jellyfin is disabled", 1)
|
|
return False
|
|
|
|
if server_2_type == "emby" and not sync_from_jelly_to_emby:
|
|
logger("Sync from jellyfin -> emby is disabled", 1)
|
|
return False
|
|
|
|
if server_1_type == "emby":
|
|
if server_2_type == "plex" and not sync_from_emby_to_plex:
|
|
logger("Sync from emby -> plex is disabled", 1)
|
|
return False
|
|
|
|
if server_2_type == "jellyfin" and not sync_from_emby_to_jellyfin:
|
|
logger("Sync from emby -> jellyfin is disabled", 1)
|
|
return False
|
|
|
|
if server_2_type == "emby" and not sync_from_emby_to_emby:
|
|
logger("Sync from emby -> emby is disabled", 1)
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def main_loop():
|
|
log_file = os.getenv("LOG_FILE", os.getenv("LOGFILE", "log.log"))
|
|
# Delete log_file if it exists
|
|
if os.path.exists(log_file):
|
|
os.remove(log_file)
|
|
|
|
dryrun = str_to_bool(os.getenv("DRYRUN", "False"))
|
|
logger(f"Dryrun: {dryrun}", 1)
|
|
|
|
user_mapping = os.getenv("USER_MAPPING")
|
|
if user_mapping:
|
|
user_mapping = json.loads(user_mapping.lower())
|
|
logger(f"User Mapping: {user_mapping}", 1)
|
|
|
|
library_mapping = os.getenv("LIBRARY_MAPPING")
|
|
if library_mapping:
|
|
library_mapping = json.loads(library_mapping)
|
|
logger(f"Library Mapping: {library_mapping}", 1)
|
|
|
|
# Create (black/white)lists
|
|
logger("Creating (black/white)lists", 1)
|
|
blacklist_library = os.getenv("BLACKLIST_LIBRARY", None)
|
|
whitelist_library = os.getenv("WHITELIST_LIBRARY", None)
|
|
blacklist_library_type = os.getenv("BLACKLIST_LIBRARY_TYPE", None)
|
|
whitelist_library_type = os.getenv("WHITELIST_LIBRARY_TYPE", None)
|
|
blacklist_users = os.getenv("BLACKLIST_USERS", None)
|
|
whitelist_users = os.getenv("WHITELIST_USERS", None)
|
|
|
|
(
|
|
blacklist_library,
|
|
whitelist_library,
|
|
blacklist_library_type,
|
|
whitelist_library_type,
|
|
blacklist_users,
|
|
whitelist_users,
|
|
) = setup_black_white_lists(
|
|
blacklist_library,
|
|
whitelist_library,
|
|
blacklist_library_type,
|
|
whitelist_library_type,
|
|
blacklist_users,
|
|
whitelist_users,
|
|
library_mapping,
|
|
user_mapping,
|
|
)
|
|
|
|
# Create server connections
|
|
logger("Creating server connections", 1)
|
|
servers = generate_server_connections()
|
|
|
|
for server_1 in servers:
|
|
# If server is the final server in the list, then we are done with the loop
|
|
if server_1 == servers[-1]:
|
|
break
|
|
|
|
# Start server_2 at the next server in the list
|
|
for server_2 in servers[servers.index(server_1) + 1 :]:
|
|
# Check if server 1 and server 2 are going to be synced in either direction, skip if not
|
|
if not should_sync_server(
|
|
server_1[0], server_2[0]
|
|
) and not should_sync_server(server_2[0], server_1[0]):
|
|
continue
|
|
|
|
logger(f"Server 1: {server_1[0].capitalize()}: {server_1[1].info()}", 0)
|
|
logger(f"Server 2: {server_2[0].capitalize()}: {server_2[1].info()}", 0)
|
|
|
|
# Create users list
|
|
logger("Creating users list", 1)
|
|
server_1_users, server_2_users = setup_users(
|
|
server_1, server_2, blacklist_users, whitelist_users, user_mapping
|
|
)
|
|
|
|
server_1_libraries, server_2_libraries = setup_libraries(
|
|
server_1[1],
|
|
server_2[1],
|
|
blacklist_library,
|
|
blacklist_library_type,
|
|
whitelist_library,
|
|
whitelist_library_type,
|
|
library_mapping,
|
|
)
|
|
|
|
logger("Creating watched lists", 1)
|
|
server_1_watched = server_1[1].get_watched(
|
|
server_1_users, server_1_libraries
|
|
)
|
|
logger("Finished creating watched list server 1", 1)
|
|
|
|
server_2_watched = server_2[1].get_watched(
|
|
server_2_users, server_2_libraries
|
|
)
|
|
logger("Finished creating watched list server 2", 1)
|
|
|
|
logger(f"Server 1 watched: {server_1_watched}", 3)
|
|
logger(f"Server 2 watched: {server_2_watched}", 3)
|
|
|
|
logger("Cleaning Server 1 Watched", 1)
|
|
server_1_watched_filtered = cleanup_watched(
|
|
server_1_watched, server_2_watched, user_mapping, library_mapping
|
|
)
|
|
|
|
logger("Cleaning Server 2 Watched", 1)
|
|
server_2_watched_filtered = cleanup_watched(
|
|
server_2_watched, server_1_watched, user_mapping, library_mapping
|
|
)
|
|
|
|
logger(
|
|
f"server 1 watched that needs to be synced to server 2:\n{server_1_watched_filtered}",
|
|
1,
|
|
)
|
|
logger(
|
|
f"server 2 watched that needs to be synced to server 1:\n{server_2_watched_filtered}",
|
|
1,
|
|
)
|
|
|
|
if should_sync_server(server_2[0], server_1[0]):
|
|
logger(f"Syncing {server_2[1].info()} -> {server_1[1].info()}", 0)
|
|
server_1[1].update_watched(
|
|
server_2_watched_filtered,
|
|
user_mapping,
|
|
library_mapping,
|
|
dryrun,
|
|
)
|
|
|
|
if should_sync_server(server_1[0], server_2[0]):
|
|
logger(f"Syncing {server_1[1].info()} -> {server_2[1].info()}", 0)
|
|
server_2[1].update_watched(
|
|
server_1_watched_filtered,
|
|
user_mapping,
|
|
library_mapping,
|
|
dryrun,
|
|
)
|
|
|
|
|
|
def main():
|
|
run_only_once = str_to_bool(os.getenv("RUN_ONLY_ONCE", "False"))
|
|
sleep_duration = float(os.getenv("SLEEP_DURATION", "3600"))
|
|
times = []
|
|
while True:
|
|
try:
|
|
start = perf_counter()
|
|
main_loop()
|
|
end = perf_counter()
|
|
times.append(end - start)
|
|
|
|
if len(times) > 0:
|
|
logger(f"Average time: {sum(times) / len(times)}", 0)
|
|
|
|
if run_only_once:
|
|
break
|
|
|
|
logger(f"Looping in {sleep_duration}")
|
|
sleep(sleep_duration)
|
|
|
|
except Exception as error:
|
|
if isinstance(error, list):
|
|
for message in error:
|
|
logger(message, log_type=2)
|
|
else:
|
|
logger(error, log_type=2)
|
|
|
|
logger(traceback.format_exc(), 2)
|
|
|
|
if run_only_once:
|
|
break
|
|
|
|
logger(f"Retrying in {sleep_duration}", log_type=0)
|
|
sleep(sleep_duration)
|
|
|
|
except KeyboardInterrupt:
|
|
if len(times) > 0:
|
|
logger(f"Average time: {sum(times) / len(times)}", 0)
|
|
logger("Exiting", log_type=0)
|
|
os._exit(0)
|