diff --git a/.env.sample b/.env.sample index 2953a0e..b90d0e1 100644 --- a/.env.sample +++ b/.env.sample @@ -1,83 +1,86 @@ -# Global Settings - -## Do not mark any shows/movies as played and instead just output to log if they would of been marked. -DRYRUN = "True" - -## Additional logging information -DEBUG = "False" - -## Debugging level, "info" is default, "debug" is more verbose -DEBUG_LEVEL = "info" - -## If set to true then the script will only run once and then exit -RUN_ONLY_ONCE = "False" - -## How often to run the script in seconds -SLEEP_DURATION = "3600" - -## Log file where all output will be written to -LOGFILE = "log.log" - -## Timeout for requests for jellyfin -REQUEST_TIMEOUT = 300 - -## Max threads for processing -MAX_THREADS = 32 - -## Map usernames between servers in the event that they are different, order does not matter -## Comma separated for multiple options -#USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" } - -## Map libraries between servers in the even that they are different, order does not matter -## Comma separated for multiple options -#LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" } - -## 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 -#BLACKLIST_LIBRARY = "" -#WHITELIST_LIBRARY = "" -#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 -## Comma separated list for multiple servers -PLEX_BASEURL = "http://localhost:32400, https://nas:32400" - -## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ -## Comma separated list for multiple servers -PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2" - -## If not using plex token then use username and password of the server admin along with the servername -## Comma separated for multiple options -#PLEX_USERNAME = "PlexUser, PlexUser2" -#PLEX_PASSWORD = "SuperSecret, SuperSecret2" -#PLEX_SERVERNAME = "Plex Server1, Plex Server2" - -## Skip hostname validation for ssl certificates. -## Set to True if running into ssl certificate errors -SSL_BYPASS = "False" - -## control the direction of syncing. e.g. SYNC_FROM_PLEX_TO_JELLYFIN set to true will cause the updates from plex -## to be updated in jellyfin. SYNC_FROM_PLEX_TO_PLEX set to true will sync updates between multiple plex servers -SYNC_FROM_PLEX_TO_JELLYFIN = "True" -SYNC_FROM_JELLYFIN_TO_PLEX = "True" -SYNC_FROM_PLEX_TO_PLEX = "True" -SYNC_FROM_JELLYFIN_TO_JELLYFIN = "True" - - -# Jellyfin - -## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly -## Comma separated list for multiple servers -JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096" - -## 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" +# Global Settings + +## Do not mark any shows/movies as played and instead just output to log if they would of been marked. +DRYRUN = "True" + +## Additional logging information +DEBUG = "False" + +## Debugging level, "info" is default, "debug" is more verbose +DEBUG_LEVEL = "info" + +## If set to true then the script will only run once and then exit +RUN_ONLY_ONCE = "False" + +## How often to run the script in seconds +SLEEP_DURATION = "3600" + +## Log file where all output will be written to +LOGFILE = "log.log" + +## Mark file where all shows/movies that have been marked as played will be written to +MARK_FILE = "mark.log" + +## Timeout for requests for jellyfin +REQUEST_TIMEOUT = 300 + +## Max threads for processing +MAX_THREADS = 32 + +## Map usernames between servers in the event that they are different, order does not matter +## Comma separated for multiple options +#USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" } + +## Map libraries between servers in the event that they are different, order does not matter +## Comma separated for multiple options +#LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" } + +## 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 +#BLACKLIST_LIBRARY = "" +#WHITELIST_LIBRARY = "" +#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 +## Comma separated list for multiple servers +PLEX_BASEURL = "http://localhost:32400, https://nas:32400" + +## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ +## Comma separated list for multiple servers +PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2" + +## If not using plex token then use username and password of the server admin along with the servername +## Comma separated for multiple options +#PLEX_USERNAME = "PlexUser, PlexUser2" +#PLEX_PASSWORD = "SuperSecret, SuperSecret2" +#PLEX_SERVERNAME = "Plex Server1, Plex Server2" + +## Skip hostname validation for ssl certificates. +## Set to True if running into ssl certificate errors +SSL_BYPASS = "False" + +## control the direction of syncing. e.g. SYNC_FROM_PLEX_TO_JELLYFIN set to true will cause the updates from plex +## to be updated in jellyfin. SYNC_FROM_PLEX_TO_PLEX set to true will sync updates between multiple plex servers +SYNC_FROM_PLEX_TO_JELLYFIN = "True" +SYNC_FROM_JELLYFIN_TO_PLEX = "True" +SYNC_FROM_PLEX_TO_PLEX = "True" +SYNC_FROM_JELLYFIN_TO_JELLYFIN = "True" + + +# Jellyfin + +## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly +## Comma separated list for multiple servers +JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096" + +## 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" diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 08d0947..853ff22 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -26,6 +26,7 @@ If applicable, add logs to help explain your problem ideally with DEBUG set to t **Type:** - [ ] Docker Compose - [ ] Docker +- [ ] Unraid - [ ] Native **Additional context** diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4dcee0f..a5c5bdb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,8 @@ jobs: docker: runs-on: ubuntu-latest needs: pytest + env: + DEFAULT_VARIANT: alpine strategy: fail-fast: false matrix: @@ -45,14 +47,19 @@ jobs: # Do not push to ghcr.io on PRs due to permission issues ghcr.io/${{ github.repository }},enable=${{ github.event_name != 'pull_request' }} tags: | - type=raw,value=latest,enable=${{ matrix.variant == 'alpine' && github.ref_name == github.event.repository.default_branch }} - type=raw,value=dev,enable=${{ matrix.variant == 'alpine' && github.ref_name == 'dev' }} + type=raw,value=latest,enable=${{ matrix.variant == env.DEFAULT_VARIANT && github.ref_name == github.event.repository.default_branch }} + type=raw,value=dev,enable=${{ matrix.variant == env.DEFAULT_VARIANT && github.ref_name == 'dev' }} type=raw,value=latest,suffix=-${{ matrix.variant }},enable={{ is_default_branch }} type=ref,event=branch,suffix=-${{ matrix.variant }} + type=ref,event=branch,enable=${{ matrix.variant == env.DEFAULT_VARIANT }} type=ref,event=pr,suffix=-${{ matrix.variant }} + type=ref,event=pr,enable=${{ matrix.variant == env.DEFAULT_VARIANT }} type=semver,pattern={{ version }},suffix=-${{ matrix.variant }} + type=semver,pattern={{ version }},enable=${{ matrix.variant == env.DEFAULT_VARIANT }} type=semver,pattern={{ major }}.{{ minor }},suffix=-${{ matrix.variant }} + type=semver,pattern={{ major }}.{{ minor }},enable=${{ matrix.variant == env.DEFAULT_VARIANT }} type=sha,suffix=-${{ matrix.variant }} + type=sha,enable=${{ matrix.variant == env.DEFAULT_VARIANT }} - name: Set up QEMU uses: docker/setup-qemu-action@v2 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 5b1a049..03f432a 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,10 +1,12 @@ -FROM python:3-alpine +FROM python:3.11-alpine ENV DRYRUN 'True' ENV DEBUG 'True' ENV DEBUG_LEVEL 'INFO' +ENV RUN_ONLY_ONCE 'False' ENV SLEEP_DURATION '3600' ENV LOGFILE 'log.log' +ENV MARKFILE 'mark.log' ENV USER_MAPPING '' ENV LIBRARY_MAPPING '' @@ -30,12 +32,20 @@ ENV WHITELIST_LIBRARY_TYPE '' ENV BLACKLIST_USERS '' ENV WHITELIST_USERS '' + +RUN addgroup --system jellyplex_user && \ + adduser --system --no-create-home jellyplex_user --ingroup jellyplex_user && \ + mkdir -p /app && \ + chown -R jellyplex_user:jellyplex_user /app + WORKDIR /app -COPY ./requirements.txt ./ +COPY --chown=jellyplex_user:jellyplex_user ./requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt -COPY . . +COPY --chown=jellyplex_user:jellyplex_user . . + +USER jellyplex_user CMD ["python", "-u", "main.py"] diff --git a/Dockerfile.slim b/Dockerfile.slim index f667fe7..59c9a02 100644 --- a/Dockerfile.slim +++ b/Dockerfile.slim @@ -1,10 +1,12 @@ -FROM python:3-slim +FROM python:3.11-slim ENV DRYRUN 'True' ENV DEBUG 'True' ENV DEBUG_LEVEL 'INFO' +ENV RUN_ONLY_ONCE 'False' ENV SLEEP_DURATION '3600' ENV LOGFILE 'log.log' +ENV MARKFILE 'mark.log' ENV USER_MAPPING '' ENV LIBRARY_MAPPING '' @@ -30,11 +32,20 @@ ENV WHITELIST_LIBRARY_TYPE '' ENV BLACKLIST_USERS '' ENV WHITELIST_USERS '' + +RUN addgroup --system jellyplex_user && \ + adduser --system --no-create-home jellyplex_user --ingroup jellyplex_user && \ + mkdir -p /app && \ + chown -R jellyplex_user:jellyplex_user /app + WORKDIR /app -COPY ./requirements.txt ./ +COPY --chown=jellyplex_user:jellyplex_user ./requirements.txt ./ + RUN pip install --no-cache-dir -r requirements.txt -COPY . . +COPY --chown=jellyplex_user:jellyplex_user . . + +USER jellyplex_user CMD ["python", "-u", "main.py"] diff --git a/README.md b/README.md index 899425d..8b6cfdd 100644 --- a/README.md +++ b/README.md @@ -12,119 +12,37 @@ Keep in sync all your users watched history between jellyfin and plex servers lo ### Plex -* \[x] Match via Filenames +* \[x] Match via filenames * \[x] Match via provider ids -* \[x] Map usersnames +* \[x] Map usernames * \[x] Use single login -* \[x] One Way/Multi Way sync -* \[x] Sync Watched -* \[x] Sync Inprogress +* \[x] One way/multi way sync +* \[x] Sync watched +* \[x] Sync in progress ### Jellyfin -* \[x] Match via Filenames +* \[x] Match via filenames * \[x] Match via provider ids -* \[x] Map usersnames +* \[x] Map usernames * \[x] Use single login -* \[x] One Way/Multi Way sync -* \[x] Sync Watched -* \[ ] Sync Inprogress +* \[x] One way/multi way sync +* \[x] Sync watched +* \[ ] Sync in progress ### Emby -* \[ ] Match via Filenames +* \[ ] Match via filenames * \[ ] Match via provider ids -* \[ ] Map usersnames +* \[ ] Map usernames * \[ ] Use single login -* \[ ] One Way/Multi Way sync -* \[ ] Sync Watched -* \[ ] Sync Inprogress +* \[ ] One way/multi way sync +* \[ ] Sync watched +* \[ ] Sync in progress ## Configuration -```bash -# Global Settings - -## Do not mark any shows/movies as played and instead just output to log if they would of been marked. -DRYRUN = "True" - -## Additional logging information -DEBUG = "False" - -## Debugging level, "info" is default, "debug" is more verbose -DEBUG_LEVEL = "info" - -## If set to true then the script will only run once and then exit -RUN_ONLY_ONCE = "False" - -## How often to run the script in seconds -SLEEP_DURATION = "3600" - -## Log file where all output will be written to -LOGFILE = "log.log" - -## Timeout for requests for jellyfin -REQUEST_TIMEOUT = 300 - -## Map usernames between servers in the event that they are different, order does not matter -## Comma separated for multiple options -USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" } - -## Map libraries between servers in the even that they are different, order does not matter -## Comma separated for multiple options -LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" } - -## 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 -BLACKLIST_LIBRARY = "" -WHITELIST_LIBRARY = "" -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 -## Comma separated list for multiple servers -PLEX_BASEURL = "http://localhost:32400, https://nas:32400" - -## Plex token https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ -## Comma separated list for multiple servers -PLEX_TOKEN = "SuperSecretToken, SuperSecretToken2" - -## If not using plex token then use username and password of the server admin along with the servername -## Comma separated for multiple options -#PLEX_USERNAME = "PlexUser, PlexUser2" -#PLEX_PASSWORD = "SuperSecret, SuperSecret2" -#PLEX_SERVERNAME = "Plex Server1, Plex Server2" - -## Skip hostname validation for ssl certificates. -## Set to True if running into ssl certificate errors -SSL_BYPASS = "False" - - -## control the direction of syncing. e.g. SYNC_FROM_PLEX_TO_JELLYFIN set to true will cause the updates from plex -## to be updated in jellyfin. SYNC_FROM_PLEX_TO_PLEX set to true will sync updates between multiple plex servers -SYNC_FROM_PLEX_TO_JELLYFIN = "True" -SYNC_FROM_JELLYFIN_TO_PLEX = "True" -SYNC_FROM_PLEX_TO_PLEX = "True" -SYNC_FROM_JELLYFIN_TO_JELLYFIN = "True" - - -# Jellyfin - -## Jellyfin server URL, use hostname or IP address if the hostname is not resolving correctly -## Comma separated list for multiple servers -JELLYFIN_BASEURL = "http://localhost:8096, http://nas:8096" - -## 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" -``` +Full list of configuration options can be found in the [.env.sample](.env.sample) ## Installation diff --git a/docker-compose.yml b/docker-compose.yml index e3783f1..c3f0703 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,8 @@ services: - RUN_ONLY_ONCE=False - SLEEP_DURATION=3600 - LOGFILE=/tmp/log.log - - USER_MAPPING= + - MARKFILE=/tmp/mark.log + - USER_MAPPING={"user1":"user2"} - LIBRARY_MAPPING={"TV Shows":"Shows"} - BLACKLIST_LIBRARY= - WHITELIST_LIBRARY= @@ -20,10 +21,10 @@ services: - WHITELIST_LIBRARY_TYPE= - BLACKLIST_USERS= - WHITELIST_USERS= - - PLEX_BASEURL= - - PLEX_TOKEN= - - JELLYFIN_BASEURL= - - JELLYFIN_TOKEN= + - PLEX_BASEURL=https://localhost:32400 + - PLEX_TOKEN=plex_token + - JELLYFIN_BASEURL=http://localhost:8096 + - JELLYFIN_TOKEN=jelly_token - SSL_BYPASS=True - SYNC_FROM_PLEX_TO_JELLYFIN=True - SYNC_FROM_JELLYFIN_TO_PLEX=True diff --git a/requirements.txt b/requirements.txt index 027232b..332dbb6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -PlexAPI==4.15.2 +PlexAPI==4.15.5 requests==2.31.0 python-dotenv==1.0.0 -aiohttp==3.8.5 +aiohttp==3.8.6 diff --git a/src/functions.py b/src/functions.py index 49dc67e..b7ae693 100644 --- a/src/functions.py +++ b/src/functions.py @@ -5,6 +5,7 @@ from dotenv import load_dotenv load_dotenv(override=True) logfile = os.getenv("LOGFILE", "log.log") +markfile = os.getenv("MARKFILE", "mark.log") def logger(message: str, log_type=0): @@ -22,6 +23,10 @@ def logger(message: str, log_type=0): output = f"[DEBUG]: {output}" elif log_type == 4: output = f"[WARNING]: {output}" + elif log_type == 5: + output = f"[MARK]: {output}" + elif log_type == 6: + output = f"[DRYRUN]: {output}" else: output = None @@ -31,6 +36,24 @@ def logger(message: str, log_type=0): 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 # Source: https://github.com/PostHog/posthog/blob/01e184c29d2c10c43166f1d40a334abbc3f99d8a/posthog/utils.py#L668 def str_to_bool(value: any) -> bool: diff --git a/src/jellyfin.py b/src/jellyfin.py index 50555f9..faaa144 100644 --- a/src/jellyfin.py +++ b/src/jellyfin.py @@ -2,7 +2,12 @@ import asyncio, aiohttp, traceback, os from math import floor 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 ( check_skip_logic, generate_library_guids_dict, @@ -95,7 +100,7 @@ class Jellyfin: return await self.query(query, query_type, session, identifiers) results = None - headers = {"Accept": "application/json", "X-Emby-Token": self.token} + authorization = ( "MediaBrowser , " 'Client="other", ' @@ -103,8 +108,8 @@ class Jellyfin: 'DeviceId="script", ' 'Version="0.0.0"' ) - headers["X-Emby-Authorization"] = authorization - + headers = {"Accept": "application/json", "X-Emby-Token": self.token, "X-Emby-Authorization": authorization} + if query_type == "get": async with session.get( self.baseurl + query, headers=headers @@ -632,25 +637,39 @@ class Jellyfin: if movie_status: jellyfin_video_id = jellyfin_video["Id"] if movie_status["completed"]: - msg = f"{jellyfin_video.get('Name')} as watched for {user_name} in {library} for Jellyfin" + msg = f"Jellyfin: {jellyfin_video.get('Name')} as watched for {user_name} in {library}" if not dryrun: - logger(f"Marking {msg}", 0) + logger(msg, 5) await self.query( f"/Users/{user_id}/PlayedItems/{jellyfin_video_id}", "post", session, ) else: - logger(f"Dryrun {msg}", 0) + logger(msg, 6) + + log_marked( + user_name, + library, + jellyfin_video.get("Name"), + ) else: # 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: {jellyfin_video.get('Name')} as partially watched for {floor(movie_status['time'] / 60_000)} minutes for {user_name} in {library}" + """ if not dryrun: pass - # logger(f"Marked {msg}", 0) + # logger(msg, 5) else: pass - # logger(f"Dryrun {msg}", 0) + # logger(msg, 6) + + log_marked( + user_name, + library, + jellyfin_video.get("Name"), + duration=floor(movie_status["time"] / 60_000), + )""" else: logger( f"Jellyfin: Skipping movie {jellyfin_video.get('Name')} as it is not in mark list for {user_name}", @@ -799,30 +818,46 @@ class Jellyfin: jellyfin_episode_id = jellyfin_episode["Id"] if episode_status["completed"]: msg = ( - f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}" - + f" as watched for {user_name} in {library} for Jellyfin" + f"Jellyfin: {jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}" + + f" as watched for {user_name} in {library}" ) if not dryrun: - logger(f"Marked {msg}", 0) + logger(msg, 5) await self.query( f"/Users/{user_id}/PlayedItems/{jellyfin_episode_id}", "post", session, ) else: - logger(f"Dryrun {msg}", 0) + logger(msg, 6) + + log_marked( + user_name, + library, + jellyfin_episode.get("SeriesName"), + jellyfin_episode.get("Name"), + ) else: # TODO add support for partially watched episodes msg = ( - 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"Jellyfin: {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}" ) + """ if not dryrun: pass # logger(f"Marked {msg}", 0) else: pass # 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: logger( f"Jellyfin: Skipping episode {jellyfin_episode.get('Name')} as it is not in mark list for {user_name}", diff --git a/src/plex.py b/src/plex.py index df80adf..87b2b3a 100644 --- a/src/plex.py +++ b/src/plex.py @@ -10,6 +10,7 @@ from src.functions import ( search_mapping, future_thread_executor, contains_nested, + log_marked, ) from src.library import ( check_skip_logic, @@ -295,19 +296,28 @@ def update_user_watched(user, user_plex, library, videos, dryrun): ) if video_status: if video_status["completed"]: - msg = f"{movies_search.title} as watched for {user.title} in {library} for Plex" + msg = f"Plex: {movies_search.title} as watched for {user.title} in {library}" if not dryrun: - logger(f"Marked {msg}", 0) + logger(msg, 5) movies_search.markWatched() else: - logger(f"Dryrun {msg}", 0) + logger(msg, 6) + + log_marked(user.title, library, movies_search.title, None, None) 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"Plex: {movies_search.title} as partially watched for {floor(video_status['time'] / 60_000)} minutes for {user.title} in {library}" if not dryrun: - logger(f"Marked {msg}", 0) + logger(msg, 5) movies_search.updateProgress(video_status["time"]) else: - logger(f"Dryrun {msg}", 0) + logger(msg, 6) + + log_marked( + user.title, + library, + movies_search.title, + duration=video_status["time"], + ) else: logger( f"Plex: Skipping movie {movies_search.title} as it is not in mark list for {user.title}", @@ -326,19 +336,34 @@ def update_user_watched(user, user_plex, library, videos, dryrun): ) if video_status: if video_status["completed"]: - msg = f"{show_search.title} {episode_search.title} as watched for {user.title} in {library} for Plex" + msg = f"Plex: {show_search.title} {episode_search.title} as watched for {user.title} in {library}" if not dryrun: - logger(f"Marked {msg}", 0) + logger(msg, 5) episode_search.markWatched() else: - logger(f"Dryrun {msg}", 0) + logger(msg, 6) + + log_marked( + user.title, + library, + show_search.title, + episode_search.title, + ) 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"Plex: {show_search.title} {episode_search.title} as partially watched for {floor(video_status['time'] / 60_000)} minutes for {user.title} in {library}" if not dryrun: - logger(f"Marked {msg}", 0) + logger(msg, 5) episode_search.updateProgress(video_status["time"]) else: - logger(f"Dryrun {msg}", 0) + logger(msg, 6) + + log_marked( + user.title, + library, + show_search.title, + episode_search.title, + video_status["time"], + ) else: logger( f"Plex: Skipping episode {episode_search.title} as it is not in mark list for {user.title}",