Add mark list support

This commit is contained in:
Luigi311
2023-11-13 01:12:08 -07:00
parent 6ccb68aeb3
commit 2c48e89435
4 changed files with 165 additions and 84 deletions

View File

@@ -1,83 +1,86 @@
# Global Settings # Global Settings
## Do not mark any shows/movies as played and instead just output to log if they would of been marked. ## Do not mark any shows/movies as played and instead just output to log if they would of been marked.
DRYRUN = "True" DRYRUN = "True"
## Additional logging information ## Additional logging information
DEBUG = "False" DEBUG = "False"
## Debugging level, "info" is default, "debug" is more verbose ## Debugging level, "info" is default, "debug" is more verbose
DEBUG_LEVEL = "info" DEBUG_LEVEL = "info"
## If set to true then the script will only run once and then exit ## If set to true then the script will only run once and then exit
RUN_ONLY_ONCE = "False" RUN_ONLY_ONCE = "False"
## How often to run the script in seconds ## How often to run the script in seconds
SLEEP_DURATION = "3600" SLEEP_DURATION = "3600"
## Log file where all output will be written to ## Log file where all output will be written to
LOGFILE = "log.log" LOGFILE = "log.log"
## Timeout for requests for jellyfin ## Mark file where all shows/movies that have been marked as played will be written to
REQUEST_TIMEOUT = 300 MARK_FILE = "mark.log"
## Max threads for processing ## Timeout for requests for jellyfin
MAX_THREADS = 32 REQUEST_TIMEOUT = 300
## Map usernames between servers in the event that they are different, order does not matter ## Max threads for processing
## Comma separated for multiple options MAX_THREADS = 32
#USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" }
## Map usernames between servers in the event that they are different, order does not matter
## Map libraries between servers in the event that they are different, order does not matter ## Comma separated for multiple options
## Comma separated for multiple options #USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" }
#LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" }
## Map libraries between servers in the event that they are different, order does not matter
## Blacklisting/Whitelisting libraries, library types such as Movies/TV Shows, and users. Mappings apply so if the mapping for the user or library exist then both will be excluded. ## Comma separated for multiple options
## Comma separated for multiple options #LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" }
#BLACKLIST_LIBRARY = ""
#WHITELIST_LIBRARY = "" ## Blacklisting/Whitelisting libraries, library types such as Movies/TV Shows, and users. Mappings apply so if the mapping for the user or library exist then both will be excluded.
#BLACKLIST_LIBRARY_TYPE = "" ## Comma separated for multiple options
#WHITELIST_LIBRARY_TYPE = "" #BLACKLIST_LIBRARY = ""
#BLACKLIST_USERS = "" #WHITELIST_LIBRARY = ""
WHITELIST_USERS = "testuser1,testuser2" #BLACKLIST_LIBRARY_TYPE = ""
#WHITELIST_LIBRARY_TYPE = ""
#BLACKLIST_USERS = ""
WHITELIST_USERS = "testuser1,testuser2"
# Plex
## Recommended to use token as it is faster to connect as it is direct to the server instead of going through the plex servers
## URL of the plex server, use hostname or IP address if the hostname is not resolving correctly # Plex
## Comma separated list for multiple servers
PLEX_BASEURL = "http://localhost:32400, https://nas:32400" ## Recommended to use token as it is faster to connect as it is direct to the server instead of going through the plex servers
## URL of the plex server, use hostname or IP address if the hostname is not resolving correctly
## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ ## Comma separated list for multiple servers
## Comma separated list for multiple servers PLEX_BASEURL = "http://localhost:32400, https://nas:32400"
PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2"
## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/
## If not using plex token then use username and password of the server admin along with the servername ## Comma separated list for multiple servers
## Comma separated for multiple options PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2"
#PLEX_USERNAME = "PlexUser, PlexUser2"
#PLEX_PASSWORD = "SuperSecret, SuperSecret2" ## If not using plex token then use username and password of the server admin along with the servername
#PLEX_SERVERNAME = "Plex Server1, Plex Server2" ## Comma separated for multiple options
#PLEX_USERNAME = "PlexUser, PlexUser2"
## Skip hostname validation for ssl certificates. #PLEX_PASSWORD = "SuperSecret, SuperSecret2"
## Set to True if running into ssl certificate errors #PLEX_SERVERNAME = "Plex Server1, Plex Server2"
SSL_BYPASS = "False"
## Skip hostname validation for ssl certificates.
## control the direction of syncing. e.g. SYNC_FROM_PLEX_TO_JELLYFIN set to true will cause the updates from plex ## Set to True if running into ssl certificate errors
## to be updated in jellyfin. SYNC_FROM_PLEX_TO_PLEX set to true will sync updates between multiple plex servers SSL_BYPASS = "False"
SYNC_FROM_PLEX_TO_JELLYFIN = "True"
SYNC_FROM_JELLYFIN_TO_PLEX = "True" ## control the direction of syncing. e.g. SYNC_FROM_PLEX_TO_JELLYFIN set to true will cause the updates from plex
SYNC_FROM_PLEX_TO_PLEX = "True" ## to be updated in jellyfin. SYNC_FROM_PLEX_TO_PLEX set to true will sync updates between multiple plex servers
SYNC_FROM_JELLYFIN_TO_JELLYFIN = "True" SYNC_FROM_PLEX_TO_JELLYFIN = "True"
SYNC_FROM_JELLYFIN_TO_PLEX = "True"
SYNC_FROM_PLEX_TO_PLEX = "True"
# Jellyfin SYNC_FROM_JELLYFIN_TO_JELLYFIN = "True"
## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly
## Comma separated list for multiple servers # Jellyfin
JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096"
## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly
## Jellyfin api token, created manually by logging in to the jellyfin server admin dashboard and creating an api key ## Comma separated list for multiple servers
## Comma separated list for multiple servers JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096"
JELLYFIN_TOKEN = "SuperSecretToken, SuperSecretToken2"
## Jellyfin api token, created manually by logging in to the jellyfin server admin dashboard and creating an api key
## Comma separated list for multiple servers
JELLYFIN_TOKEN = "SuperSecretToken, SuperSecretToken2"

View File

@@ -5,6 +5,7 @@ from dotenv import load_dotenv
load_dotenv(override=True) load_dotenv(override=True)
logfile = os.getenv("LOGFILE", "log.log") logfile = os.getenv("LOGFILE", "log.log")
markfile = os.getenv("MARK_FILE", "mark.log")
def logger(message: str, log_type=0): def logger(message: str, log_type=0):
@@ -31,6 +32,24 @@ def logger(message: str, log_type=0):
file.write(output + "\n") file.write(output + "\n")
def log_marked(
username: str, library: str, movie_show: str, episode: str = None, duration=None
):
if markfile is None:
return
output = f"{username}/{library}/{movie_show}"
if episode:
output += f"/{episode}"
if duration:
output += f"/{duration}"
file = open(f"{markfile}", "a", encoding="utf-8")
file.write(output + "\n")
# Reimplementation of distutils.util.strtobool due to it being deprecated # Reimplementation of distutils.util.strtobool due to it being deprecated
# Source: https://github.com/PostHog/posthog/blob/01e184c29d2c10c43166f1d40a334abbc3f99d8a/posthog/utils.py#L668 # Source: https://github.com/PostHog/posthog/blob/01e184c29d2c10c43166f1d40a334abbc3f99d8a/posthog/utils.py#L668
def str_to_bool(value: any) -> bool: def str_to_bool(value: any) -> bool:

View File

@@ -2,7 +2,12 @@ import asyncio, aiohttp, traceback, os
from math import floor from math import floor
from dotenv import load_dotenv from dotenv import load_dotenv
from src.functions import logger, search_mapping, contains_nested from src.functions import (
logger,
search_mapping,
contains_nested,
log_marked,
)
from src.library import ( from src.library import (
check_skip_logic, check_skip_logic,
generate_library_guids_dict, generate_library_guids_dict,
@@ -642,6 +647,12 @@ class Jellyfin:
) )
else: else:
logger(f"Dryrun {msg}", 0) logger(f"Dryrun {msg}", 0)
log_marked(
user_name,
library,
jellyfin_video.get("Name"),
)
else: else:
# TODO add support for partially watched movies # TODO add support for partially watched movies
msg = f"{jellyfin_video.get('Name')} as partially watched for {floor(movie_status['time'] / 60_000)} minutes for {user_name} in {library} for Jellyfin" msg = f"{jellyfin_video.get('Name')} as partially watched for {floor(movie_status['time'] / 60_000)} minutes for {user_name} in {library} for Jellyfin"
@@ -651,6 +662,13 @@ class Jellyfin:
else: else:
pass pass
# logger(f"Dryrun {msg}", 0) # logger(f"Dryrun {msg}", 0)
log_marked(
user_name,
library,
jellyfin_video.get("Name"),
duration=floor(movie_status["time"] / 60_000),
)
else: else:
logger( logger(
f"Jellyfin: Skipping movie {jellyfin_video.get('Name')} as it is not in mark list for {user_name}", f"Jellyfin: Skipping movie {jellyfin_video.get('Name')} as it is not in mark list for {user_name}",
@@ -811,18 +829,34 @@ class Jellyfin:
) )
else: else:
logger(f"Dryrun {msg}", 0) logger(f"Dryrun {msg}", 0)
log_marked(
user_name,
library,
jellyfin_episode.get("SeriesName"),
jellyfin_episode.get("Name"),
)
else: else:
# TODO add support for partially watched episodes # TODO add support for partially watched episodes
msg = ( msg = (
f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}" f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}"
+ f" as partially watched for {floor(episode_status['time'] / 60_000)} minutes for {user_name} in {library} for Jellyfin" + f" as partially watched for {floor(episode_status['time'] / 60_000)} minutes for {user_name} in {library} for Jellyfin"
) )
"""
if not dryrun: if not dryrun:
pass pass
# logger(f"Marked {msg}", 0) # logger(f"Marked {msg}", 0)
else: else:
pass pass
# logger(f"Dryrun {msg}", 0) # logger(f"Dryrun {msg}", 0)
log_marked(
user_name,
library,
jellyfin_episode.get("SeriesName"),
jellyfin_episode.get('Name'),
duration=floor(episode_status["time"] / 60_000),
)"""
else: else:
logger( logger(
f"Jellyfin: Skipping episode {jellyfin_episode.get('Name')} as it is not in mark list for {user_name}", f"Jellyfin: Skipping episode {jellyfin_episode.get('Name')} as it is not in mark list for {user_name}",

View File

@@ -10,6 +10,7 @@ from src.functions import (
search_mapping, search_mapping,
future_thread_executor, future_thread_executor,
contains_nested, contains_nested,
log_marked,
) )
from src.library import ( from src.library import (
check_skip_logic, check_skip_logic,
@@ -301,6 +302,8 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
movies_search.markWatched() movies_search.markWatched()
else: else:
logger(f"Dryrun {msg}", 0) logger(f"Dryrun {msg}", 0)
log_marked(user.title, library, movies_search.title, None, None)
elif video_status["time"] > 60_000: elif video_status["time"] > 60_000:
msg = f"{movies_search.title} as partially watched for {floor(video_status['time'] / 60_000)} minutes for {user.title} in {library} for Plex" msg = f"{movies_search.title} as partially watched for {floor(video_status['time'] / 60_000)} minutes for {user.title} in {library} for Plex"
if not dryrun: if not dryrun:
@@ -308,6 +311,13 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
movies_search.updateProgress(video_status["time"]) movies_search.updateProgress(video_status["time"])
else: else:
logger(f"Dryrun {msg}", 0) logger(f"Dryrun {msg}", 0)
log_marked(
user.title,
library,
movies_search.title,
duration=video_status["time"],
)
else: else:
logger( logger(
f"Plex: Skipping movie {movies_search.title} as it is not in mark list for {user.title}", f"Plex: Skipping movie {movies_search.title} as it is not in mark list for {user.title}",
@@ -332,6 +342,13 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
episode_search.markWatched() episode_search.markWatched()
else: else:
logger(f"Dryrun {msg}", 0) logger(f"Dryrun {msg}", 0)
log_marked(
user.title,
library,
show_search.title,
episode_search.title,
)
else: else:
msg = f"{show_search.title} {episode_search.title} as partially watched for {floor(video_status['time'] / 60_000)} minutes for {user.title} in {library} for Plex" msg = f"{show_search.title} {episode_search.title} as partially watched for {floor(video_status['time'] / 60_000)} minutes for {user.title} in {library} for Plex"
if not dryrun: if not dryrun:
@@ -339,6 +356,14 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
episode_search.updateProgress(video_status["time"]) episode_search.updateProgress(video_status["time"])
else: else:
logger(f"Dryrun {msg}", 0) logger(f"Dryrun {msg}", 0)
log_marked(
user.title,
library,
show_search.title,
episode_search.title,
video_status["time"],
)
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}",