Add logger, add looping
parent
8b26e50346
commit
93da9eec34
49
main.py
49
main.py
|
|
@ -1,6 +1,7 @@
|
||||||
import copy, os
|
import copy, os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from src.functions import logger, str_to_bool
|
||||||
from src.plex import Plex
|
from src.plex import Plex
|
||||||
from src.jellyfin import Jellyfin
|
from src.jellyfin import Jellyfin
|
||||||
|
|
||||||
|
|
@ -60,7 +61,14 @@ def cleanup_watched(watched_list_1, watched_list_2):
|
||||||
|
|
||||||
return modified_watched_list_1
|
return modified_watched_list_1
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def main():
|
||||||
|
logfile = os.getenv("LOGFILE","log.log")
|
||||||
|
# Delete logfile if it exists
|
||||||
|
if os.path.exists(logfile):
|
||||||
|
os.remove(logfile)
|
||||||
|
|
||||||
|
dryrun = str_to_bool(os.getenv("DRYRUN", "False"))
|
||||||
|
logger(f"Dryrun: {dryrun}", 1)
|
||||||
plex = Plex()
|
plex = Plex()
|
||||||
jellyfin = Jellyfin()
|
jellyfin = Jellyfin()
|
||||||
|
|
||||||
|
|
@ -71,6 +79,7 @@ if __name__ == "__main__":
|
||||||
blacklist_library = [x.lower().trim() for x in blacklist_library]
|
blacklist_library = [x.lower().trim() for x in blacklist_library]
|
||||||
else:
|
else:
|
||||||
blacklist_library = []
|
blacklist_library = []
|
||||||
|
logger(f"Blacklist Library: {blacklist_library}", 1)
|
||||||
|
|
||||||
whitelist_library = os.getenv("WHITELIST_LIBRARY")
|
whitelist_library = os.getenv("WHITELIST_LIBRARY")
|
||||||
if whitelist_library:
|
if whitelist_library:
|
||||||
|
|
@ -79,7 +88,7 @@ if __name__ == "__main__":
|
||||||
whitelist_library = [x.lower().strip() for x in whitelist_library]
|
whitelist_library = [x.lower().strip() for x in whitelist_library]
|
||||||
else:
|
else:
|
||||||
whitelist_library = []
|
whitelist_library = []
|
||||||
|
logger(f"Whitelist Library: {whitelist_library}", 1)
|
||||||
|
|
||||||
blacklist_library_type = os.getenv("BLACKLIST_LIBRARY_TYPE")
|
blacklist_library_type = os.getenv("BLACKLIST_LIBRARY_TYPE")
|
||||||
if blacklist_library_type:
|
if blacklist_library_type:
|
||||||
|
|
@ -88,6 +97,7 @@ if __name__ == "__main__":
|
||||||
blacklist_library_type = [x.lower().strip() for x in blacklist_library_type]
|
blacklist_library_type = [x.lower().strip() for x in blacklist_library_type]
|
||||||
else:
|
else:
|
||||||
blacklist_library_type = []
|
blacklist_library_type = []
|
||||||
|
logger(f"Blacklist Library Type: {blacklist_library_type}", 1)
|
||||||
|
|
||||||
whitelist_library_type = os.getenv("WHITELIST_LIBRARY_TYPE")
|
whitelist_library_type = os.getenv("WHITELIST_LIBRARY_TYPE")
|
||||||
if whitelist_library_type:
|
if whitelist_library_type:
|
||||||
|
|
@ -96,15 +106,16 @@ if __name__ == "__main__":
|
||||||
whitelist_library_type = [x.lower().strip() for x in whitelist_library_type]
|
whitelist_library_type = [x.lower().strip() for x in whitelist_library_type]
|
||||||
else:
|
else:
|
||||||
whitelist_library_type = []
|
whitelist_library_type = []
|
||||||
|
logger(f"Whitelist Library Type: {whitelist_library_type}", 1)
|
||||||
|
|
||||||
blacklist_users = os.getenv("BLACKLIST_USERS")
|
blacklist_users = os.getenv("BLACKLIST_USERS")
|
||||||
if blacklist_users:
|
if blacklist_users:
|
||||||
if len(blacklist_users) > 0:
|
if len(blacklist_users) > 0:
|
||||||
blacklist_users = blacklist_users.split(",")
|
blacklist_users = blacklist_users.split(",")
|
||||||
blacklist_users = [x.lower().strip() for x in blacklist_users]
|
blacklist_users = [x.lower().strip() for x in blacklist_users]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
blacklist_users = []
|
blacklist_users = []
|
||||||
|
logger(f"Blacklist Users: {blacklist_users}", 1)
|
||||||
|
|
||||||
whitelist_users = os.getenv("WHITELIST_USERS")
|
whitelist_users = os.getenv("WHITELIST_USERS")
|
||||||
# print whitelist_users object type
|
# print whitelist_users object type
|
||||||
|
|
@ -116,20 +127,21 @@ if __name__ == "__main__":
|
||||||
whitelist_users = []
|
whitelist_users = []
|
||||||
else:
|
else:
|
||||||
whitelist_users = []
|
whitelist_users = []
|
||||||
|
logger(f"Whitelist Users: {whitelist_users}", 1)
|
||||||
|
|
||||||
users_filtered = []
|
|
||||||
|
|
||||||
# generate list of users from plex.users
|
# generate list of users from plex.users
|
||||||
plex_users = [ x.title.lower() for x in plex.users ]
|
plex_users = [ x.title.lower() for x in plex.users ]
|
||||||
jellyfin_users = [ key.lower() for key in jellyfin.users.keys() ]
|
jellyfin_users = [ key.lower() for key in jellyfin.users.keys() ]
|
||||||
|
|
||||||
# combined list of overlapping users from plex and jellyfin
|
# combined list of overlapping users from plex and jellyfin
|
||||||
users = [x for x in plex_users if x in jellyfin_users]
|
users = [x for x in plex_users if x in jellyfin_users]
|
||||||
|
logger(f"User list that exist on both servers {users}", 1)
|
||||||
|
|
||||||
|
users_filtered = []
|
||||||
for user in users:
|
for user in users:
|
||||||
# whitelist_user is not empty and user lowercase is not in whitelist lowercase
|
# whitelist_user is not empty and user lowercase is not in whitelist lowercase
|
||||||
if len(whitelist_users) > 0 and user.lower() not in whitelist_users:
|
if len(whitelist_users) > 0 and user.lower() not in whitelist_users:
|
||||||
print(f"{user} is not in whitelist")
|
logger(f"{user} is not in whitelist", 1)
|
||||||
else:
|
else:
|
||||||
if user.lower() not in blacklist_users:
|
if user.lower() not in blacklist_users:
|
||||||
users_filtered.append(user)
|
users_filtered.append(user)
|
||||||
|
|
@ -144,10 +156,15 @@ if __name__ == "__main__":
|
||||||
if jellyfin_user.lower() in users_filtered:
|
if jellyfin_user.lower() in users_filtered:
|
||||||
jellyfin_users[jellyfin_user] = jellyfin_id
|
jellyfin_users[jellyfin_user] = jellyfin_id
|
||||||
|
|
||||||
|
logger(f"plex_users: {plex_users}", 1)
|
||||||
|
logger(f"jellyfin_users: {jellyfin_users}", 1)
|
||||||
|
|
||||||
if len(plex_users) == 0:
|
if len(plex_users) == 0:
|
||||||
|
logger("No users found", 2)
|
||||||
raise Exception("No users found")
|
raise Exception("No users found")
|
||||||
|
|
||||||
if len(jellyfin_users) == 0:
|
if len(jellyfin_users) == 0:
|
||||||
|
logger("No users found", 2)
|
||||||
raise Exception("No users found")
|
raise Exception("No users found")
|
||||||
|
|
||||||
plex_watched = plex.get_plex_watched(plex_users, blacklist_library, whitelist_library, blacklist_library_type, whitelist_library_type)
|
plex_watched = plex.get_plex_watched(plex_users, blacklist_library, whitelist_library, blacklist_library_type, whitelist_library_type)
|
||||||
|
|
@ -158,14 +175,18 @@ if __name__ == "__main__":
|
||||||
jellyfin_watched_filtered = copy.deepcopy(jellyfin_watched)
|
jellyfin_watched_filtered = copy.deepcopy(jellyfin_watched)
|
||||||
|
|
||||||
plex_watched = cleanup_watched(plex_watched_filtered, jellyfin_watched_filtered)
|
plex_watched = cleanup_watched(plex_watched_filtered, jellyfin_watched_filtered)
|
||||||
print(f"Plex Watched: {plex_watched}")
|
logger(f"plex_watched that needs to be synced to jellyfin:\n{plex_watched}", 1)
|
||||||
|
|
||||||
jellyfin_watched = cleanup_watched(jellyfin_watched_filtered, plex_watched_filtered)
|
jellyfin_watched = cleanup_watched(jellyfin_watched_filtered, plex_watched_filtered)
|
||||||
print(f"Jellyfin Watched: {jellyfin_watched}")
|
logger(f"jellyfin_watched that needs to be synced to plex:\n{jellyfin_watched}", 1)
|
||||||
|
|
||||||
# Update watched status
|
# Update watched status
|
||||||
plex.update_watched(jellyfin_watched)
|
plex.update_watched(jellyfin_watched, dryrun)
|
||||||
print("Plex watched updated")
|
jellyfin.update_watched(plex_watched, dryrun)
|
||||||
|
|
||||||
jellyfin.update_watched(plex_watched)
|
|
||||||
print("Jellyfin watched updated")
|
if __name__ == "__main__":
|
||||||
|
sleep_timer = float(os.getenv("SLEEP_TIMER", "3600"))
|
||||||
|
while(True):
|
||||||
|
main()
|
||||||
|
sleep(sleep_timer)
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
logfile = os.getenv("LOGFILE","log.log")
|
||||||
|
|
||||||
|
def logger(message, log_type=0):
|
||||||
|
|
||||||
|
output = str(message)
|
||||||
|
if log_type == 0:
|
||||||
|
pass
|
||||||
|
elif log_type == 1:
|
||||||
|
output = f"[INFO]: {output}"
|
||||||
|
elif log_type == 2:
|
||||||
|
output = f"[ERROR]: {output}"
|
||||||
|
else:
|
||||||
|
output = None
|
||||||
|
|
||||||
|
if output is not None:
|
||||||
|
print(output)
|
||||||
|
file = open(logfile, "a", encoding="utf-8")
|
||||||
|
file.write(output + "\n")
|
||||||
|
|
||||||
|
# Reimplementation of distutils.util.strtobool due to it being deprecated
|
||||||
|
# Source: https://github.com/PostHog/posthog/blob/01e184c29d2c10c43166f1d40a334abbc3f99d8a/posthog/utils.py#L668
|
||||||
|
def str_to_bool(value: any) -> bool:
|
||||||
|
if not value:
|
||||||
|
return False
|
||||||
|
return str(value).lower() in ("y", "yes", "t", "true", "on", "1")
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import requests, os
|
import requests, os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from src.functions import logger
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|
@ -39,8 +40,8 @@ class Jellyfin():
|
||||||
|
|
||||||
return response.json()
|
return response.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger(e, 2)
|
||||||
print(response)
|
logger(response, 2)
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
users = {}
|
users = {}
|
||||||
|
|
@ -66,7 +67,7 @@ class Jellyfin():
|
||||||
|
|
||||||
for library in libraries:
|
for library in libraries:
|
||||||
library_title = library["Name"]
|
library_title = library["Name"]
|
||||||
print(f"Jellyfin: Generating watched for {user_name} in library {library_title}")
|
logger(f"Jellyfin: Generating watched for {user_name} in library {library_title}", 0)
|
||||||
|
|
||||||
library_id = library["Id"]
|
library_id = library["Id"]
|
||||||
# if whitelist is not empty and library is not in whitelist
|
# if whitelist is not empty and library is not in whitelist
|
||||||
|
|
@ -128,7 +129,7 @@ class Jellyfin():
|
||||||
|
|
||||||
return users_watched
|
return users_watched
|
||||||
|
|
||||||
def update_watched(self, watched_list):
|
def update_watched(self, watched_list, dryrun=False):
|
||||||
for user, libraries in watched_list.items():
|
for user, libraries in watched_list.items():
|
||||||
|
|
||||||
user_id = None
|
user_id = None
|
||||||
|
|
@ -138,7 +139,7 @@ class Jellyfin():
|
||||||
break
|
break
|
||||||
|
|
||||||
if not user_id:
|
if not user_id:
|
||||||
print(f"{user} not found in Jellyfin")
|
logger(f"{user} not found in Jellyfin", 2)
|
||||||
break
|
break
|
||||||
|
|
||||||
jellyfin_libraries = self.query(f"/Users/{user_id}/Views", "get")["Items"]
|
jellyfin_libraries = self.query(f"/Users/{user_id}/Views", "get")["Items"]
|
||||||
|
|
@ -162,8 +163,12 @@ class Jellyfin():
|
||||||
for video in videos:
|
for video in videos:
|
||||||
for key, value in jellyfin_video["ProviderIds"].items():
|
for key, value in jellyfin_video["ProviderIds"].items():
|
||||||
if key.lower() in video.keys() and value.lower() == video[key.lower()].lower():
|
if key.lower() in video.keys() and value.lower() == video[key.lower()].lower():
|
||||||
print(f"Marking {jellyfin_video['Name']} as watched for {user}")
|
msg = f"{jellyfin_video['Name']} as watched for {user}"
|
||||||
self.query(f"/Users/{user_id}/PlayedItems/{jellyfin_video_id}", "post")
|
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)
|
||||||
break
|
break
|
||||||
|
|
||||||
# TV Shows
|
# TV Shows
|
||||||
|
|
@ -183,7 +188,11 @@ class Jellyfin():
|
||||||
for episode in videos[show][season]:
|
for episode in videos[show][season]:
|
||||||
for key, value in jellyfin_episode["ProviderIds"].items():
|
for key, value in jellyfin_episode["ProviderIds"].items():
|
||||||
if key.lower() in episode.keys() and value.lower() == episode[key.lower()].lower():
|
if key.lower() in episode.keys() and value.lower() == episode[key.lower()].lower():
|
||||||
print(f"Marked {jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} {jellyfin_episode['Name']} as watched for {user} in Jellyfin")
|
msg = f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} {jellyfin_episode['Name']} as watched for {user} in Jellyfin"
|
||||||
self.query(f"/Users/{user_id}/PlayedItems/{jellyfin_episode_id}", "post")
|
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)
|
||||||
break
|
break
|
||||||
|
|
||||||
33
src/plex.py
33
src/plex.py
|
|
@ -1,5 +1,7 @@
|
||||||
import re, os
|
import re, os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from src.functions import logger
|
||||||
from plexapi.server import PlexServer
|
from plexapi.server import PlexServer
|
||||||
from plexapi.myplex import MyPlexAccount
|
from plexapi.myplex import MyPlexAccount
|
||||||
|
|
||||||
|
|
@ -23,14 +25,13 @@ class Plex:
|
||||||
|
|
||||||
def plex_login(self):
|
def plex_login(self):
|
||||||
if self.baseurl:
|
if self.baseurl:
|
||||||
# if self.username and self.password are not None or empty strings
|
if self.token:
|
||||||
if self.username and self.password:
|
# Login via token
|
||||||
|
plex = PlexServer(self.baseurl, self.token)
|
||||||
|
elif self.username and self.password:
|
||||||
# Login via plex account
|
# Login via plex account
|
||||||
account = MyPlexAccount(self.username, self.password)
|
account = MyPlexAccount(self.username, self.password)
|
||||||
plex = account.resource(self.baseurl).connect()
|
plex = account.resource(self.baseurl).connect()
|
||||||
elif self.token:
|
|
||||||
# Login via token
|
|
||||||
plex = PlexServer(self.baseurl, self.token)
|
|
||||||
else:
|
else:
|
||||||
raise Exception("No plex credentials provided")
|
raise Exception("No plex credentials provided")
|
||||||
else:
|
else:
|
||||||
|
|
@ -106,7 +107,7 @@ class Plex:
|
||||||
else:
|
else:
|
||||||
if library_title.lower() not in [x.lower() for x in blacklist_library] and library.type not in [x.lower() for x in blacklist_library_type]:
|
if library_title.lower() not in [x.lower() for x in blacklist_library] and library.type not in [x.lower() for x in blacklist_library_type]:
|
||||||
for user in users:
|
for user in users:
|
||||||
print(f"Plex: Generating watched for {user.title} in library {library_title}")
|
logger(f"Plex: Generating watched for {user.title} in library {library_title}", 0)
|
||||||
user_name = user.title.lower()
|
user_name = user.title.lower()
|
||||||
watched = self.get_plex_user_watched(user, library)
|
watched = self.get_plex_user_watched(user, library)
|
||||||
if watched:
|
if watched:
|
||||||
|
|
@ -118,7 +119,7 @@ class Plex:
|
||||||
|
|
||||||
return users_watched
|
return users_watched
|
||||||
|
|
||||||
def update_watched(self, watched_list):
|
def update_watched(self, watched_list, dryrun=False):
|
||||||
for user, libraries in watched_list.items():
|
for user, libraries in watched_list.items():
|
||||||
for index, value in enumerate(self.users):
|
for index, value in enumerate(self.users):
|
||||||
if user.lower() == value.title.lower():
|
if user.lower() == value.title.lower():
|
||||||
|
|
@ -130,7 +131,7 @@ class Plex:
|
||||||
else:
|
else:
|
||||||
user_plex = PlexServer(self.baseurl, user.get_token(self.plex.machineIdentifier))
|
user_plex = PlexServer(self.baseurl, user.get_token(self.plex.machineIdentifier))
|
||||||
|
|
||||||
print(f"Updating watched for {user.title}")
|
logger(f"Updating watched for {user.title}", 1)
|
||||||
for library, videos in libraries.items():
|
for library, videos in libraries.items():
|
||||||
library_videos = user_plex.library.section(library)
|
library_videos = user_plex.library.section(library)
|
||||||
|
|
||||||
|
|
@ -143,8 +144,12 @@ class Plex:
|
||||||
for video_keys, video_id in video.items():
|
for video_keys, video_id in video.items():
|
||||||
if video_keys == guid_source and video_id == guid_id:
|
if video_keys == guid_source and video_id == guid_id:
|
||||||
if movies_search.viewCount == 0:
|
if movies_search.viewCount == 0:
|
||||||
movies_search.markWatched()
|
msg = f"{movies_search.title} watched"
|
||||||
print(f"Marked {movies_search.title} watched")
|
if not dryrun:
|
||||||
|
logger(f"Marked {msg}", 0)
|
||||||
|
movies_search.markWatched()
|
||||||
|
else:
|
||||||
|
logger(f"Dyrun {msg}", 0)
|
||||||
break
|
break
|
||||||
|
|
||||||
elif library_videos.type == "show":
|
elif library_videos.type == "show":
|
||||||
|
|
@ -161,6 +166,10 @@ class Plex:
|
||||||
for episode_keys, episode_id in episode.items():
|
for episode_keys, episode_id in episode.items():
|
||||||
if episode_keys == guid_source and episode_id == guid_id:
|
if episode_keys == guid_source and episode_id == guid_id:
|
||||||
if episode_search.viewCount == 0:
|
if episode_search.viewCount == 0:
|
||||||
episode_search.markWatched()
|
msg = f"{show_search.title} {season_search.title} {episode_search.title} as watched for {user.title} in Plex"
|
||||||
print(f"Marked {show_search.title} {season_search.title} {episode_search.title} as watched for {user.title} in Plex")
|
if not dryrun:
|
||||||
|
logger(f"Marked {msg}", 0)
|
||||||
|
episode_search.markWatched()
|
||||||
|
else:
|
||||||
|
logger(f"Dryrun {msg}", 0)
|
||||||
break
|
break
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue