Merge pull request #114 from luigi311/dev
Add markfile, Fix documentation, Add default variant, Non-root docker container
This commit is contained in:
@@ -18,6 +18,9 @@ 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"
|
||||||
|
|
||||||
|
## 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
|
## Timeout for requests for jellyfin
|
||||||
REQUEST_TIMEOUT = 300
|
REQUEST_TIMEOUT = 300
|
||||||
|
|
||||||
@@ -28,7 +31,7 @@ MAX_THREADS = 32
|
|||||||
## Comma separated for multiple options
|
## Comma separated for multiple options
|
||||||
#USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" }
|
#USER_MAPPING = { "testuser2": "testuser3", "testuser1":"testuser4" }
|
||||||
|
|
||||||
## Map libraries between servers in the even 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
|
||||||
#LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" }
|
#LIBRARY_MAPPING = { "Shows": "TV Shows", "Movie": "Movies" }
|
||||||
|
|
||||||
|
|||||||
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -26,6 +26,7 @@ If applicable, add logs to help explain your problem ideally with DEBUG set to t
|
|||||||
**Type:**
|
**Type:**
|
||||||
- [ ] Docker Compose
|
- [ ] Docker Compose
|
||||||
- [ ] Docker
|
- [ ] Docker
|
||||||
|
- [ ] Unraid
|
||||||
- [ ] Native
|
- [ ] Native
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
|
|||||||
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -24,6 +24,8 @@ jobs:
|
|||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: pytest
|
needs: pytest
|
||||||
|
env:
|
||||||
|
DEFAULT_VARIANT: alpine
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -45,14 +47,19 @@ jobs:
|
|||||||
# Do not push to ghcr.io on PRs due to permission issues
|
# Do not push to ghcr.io on PRs due to permission issues
|
||||||
ghcr.io/${{ github.repository }},enable=${{ github.event_name != 'pull_request' }}
|
ghcr.io/${{ github.repository }},enable=${{ github.event_name != 'pull_request' }}
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest,enable=${{ matrix.variant == 'alpine' && github.ref_name == github.event.repository.default_branch }}
|
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 == 'alpine' && github.ref_name == 'dev' }}
|
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=raw,value=latest,suffix=-${{ matrix.variant }},enable={{ is_default_branch }}
|
||||||
type=ref,event=branch,suffix=-${{ matrix.variant }}
|
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,suffix=-${{ matrix.variant }}
|
||||||
|
type=ref,event=pr,enable=${{ matrix.variant == env.DEFAULT_VARIANT }}
|
||||||
type=semver,pattern={{ version }},suffix=-${{ matrix.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 }},suffix=-${{ matrix.variant }}
|
||||||
|
type=semver,pattern={{ major }}.{{ minor }},enable=${{ matrix.variant == env.DEFAULT_VARIANT }}
|
||||||
type=sha,suffix=-${{ matrix.variant }}
|
type=sha,suffix=-${{ matrix.variant }}
|
||||||
|
type=sha,enable=${{ matrix.variant == env.DEFAULT_VARIANT }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
FROM python:3-alpine
|
FROM python:3.11-alpine
|
||||||
|
|
||||||
ENV DRYRUN 'True'
|
ENV DRYRUN 'True'
|
||||||
ENV DEBUG 'True'
|
ENV DEBUG 'True'
|
||||||
ENV DEBUG_LEVEL 'INFO'
|
ENV DEBUG_LEVEL 'INFO'
|
||||||
|
ENV RUN_ONLY_ONCE 'False'
|
||||||
ENV SLEEP_DURATION '3600'
|
ENV SLEEP_DURATION '3600'
|
||||||
ENV LOGFILE 'log.log'
|
ENV LOGFILE 'log.log'
|
||||||
|
ENV MARKFILE 'mark.log'
|
||||||
|
|
||||||
ENV USER_MAPPING ''
|
ENV USER_MAPPING ''
|
||||||
ENV LIBRARY_MAPPING ''
|
ENV LIBRARY_MAPPING ''
|
||||||
@@ -30,12 +32,20 @@ ENV WHITELIST_LIBRARY_TYPE ''
|
|||||||
ENV BLACKLIST_USERS ''
|
ENV BLACKLIST_USERS ''
|
||||||
ENV WHITELIST_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
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ./requirements.txt ./
|
COPY --chown=jellyplex_user:jellyplex_user ./requirements.txt ./
|
||||||
|
|
||||||
RUN pip install --no-cache-dir -r 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"]
|
CMD ["python", "-u", "main.py"]
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
FROM python:3-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
ENV DRYRUN 'True'
|
ENV DRYRUN 'True'
|
||||||
ENV DEBUG 'True'
|
ENV DEBUG 'True'
|
||||||
ENV DEBUG_LEVEL 'INFO'
|
ENV DEBUG_LEVEL 'INFO'
|
||||||
|
ENV RUN_ONLY_ONCE 'False'
|
||||||
ENV SLEEP_DURATION '3600'
|
ENV SLEEP_DURATION '3600'
|
||||||
ENV LOGFILE 'log.log'
|
ENV LOGFILE 'log.log'
|
||||||
|
ENV MARKFILE 'mark.log'
|
||||||
|
|
||||||
ENV USER_MAPPING ''
|
ENV USER_MAPPING ''
|
||||||
ENV LIBRARY_MAPPING ''
|
ENV LIBRARY_MAPPING ''
|
||||||
@@ -30,11 +32,20 @@ ENV WHITELIST_LIBRARY_TYPE ''
|
|||||||
ENV BLACKLIST_USERS ''
|
ENV BLACKLIST_USERS ''
|
||||||
ENV WHITELIST_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
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ./requirements.txt ./
|
COPY --chown=jellyplex_user:jellyplex_user ./requirements.txt ./
|
||||||
|
|
||||||
RUN pip install --no-cache-dir -r 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"]
|
CMD ["python", "-u", "main.py"]
|
||||||
|
|||||||
114
README.md
114
README.md
@@ -12,119 +12,37 @@ Keep in sync all your users watched history between jellyfin and plex servers lo
|
|||||||
|
|
||||||
### Plex
|
### Plex
|
||||||
|
|
||||||
* \[x] Match via Filenames
|
* \[x] Match via filenames
|
||||||
* \[x] Match via provider ids
|
* \[x] Match via provider ids
|
||||||
* \[x] Map usersnames
|
* \[x] Map usernames
|
||||||
* \[x] Use single login
|
* \[x] Use single login
|
||||||
* \[x] One Way/Multi Way sync
|
* \[x] One way/multi way sync
|
||||||
* \[x] Sync Watched
|
* \[x] Sync watched
|
||||||
* \[x] Sync Inprogress
|
* \[x] Sync in progress
|
||||||
|
|
||||||
### Jellyfin
|
### Jellyfin
|
||||||
|
|
||||||
* \[x] Match via Filenames
|
* \[x] Match via filenames
|
||||||
* \[x] Match via provider ids
|
* \[x] Match via provider ids
|
||||||
* \[x] Map usersnames
|
* \[x] Map usernames
|
||||||
* \[x] Use single login
|
* \[x] Use single login
|
||||||
* \[x] One Way/Multi Way sync
|
* \[x] One way/multi way sync
|
||||||
* \[x] Sync Watched
|
* \[x] Sync watched
|
||||||
* \[ ] Sync Inprogress
|
* \[ ] Sync in progress
|
||||||
|
|
||||||
### Emby
|
### Emby
|
||||||
|
|
||||||
* \[ ] Match via Filenames
|
* \[ ] Match via filenames
|
||||||
* \[ ] Match via provider ids
|
* \[ ] Match via provider ids
|
||||||
* \[ ] Map usersnames
|
* \[ ] Map usernames
|
||||||
* \[ ] Use single login
|
* \[ ] Use single login
|
||||||
* \[ ] One Way/Multi Way sync
|
* \[ ] One way/multi way sync
|
||||||
* \[ ] Sync Watched
|
* \[ ] Sync watched
|
||||||
* \[ ] Sync Inprogress
|
* \[ ] Sync in progress
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
```bash
|
Full list of configuration options can be found in the [.env.sample](.env.sample)
|
||||||
# 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"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ services:
|
|||||||
- RUN_ONLY_ONCE=False
|
- RUN_ONLY_ONCE=False
|
||||||
- SLEEP_DURATION=3600
|
- SLEEP_DURATION=3600
|
||||||
- LOGFILE=/tmp/log.log
|
- LOGFILE=/tmp/log.log
|
||||||
- USER_MAPPING=
|
- MARKFILE=/tmp/mark.log
|
||||||
|
- USER_MAPPING={"user1":"user2"}
|
||||||
- LIBRARY_MAPPING={"TV Shows":"Shows"}
|
- LIBRARY_MAPPING={"TV Shows":"Shows"}
|
||||||
- BLACKLIST_LIBRARY=
|
- BLACKLIST_LIBRARY=
|
||||||
- WHITELIST_LIBRARY=
|
- WHITELIST_LIBRARY=
|
||||||
@@ -20,10 +21,10 @@ services:
|
|||||||
- WHITELIST_LIBRARY_TYPE=
|
- WHITELIST_LIBRARY_TYPE=
|
||||||
- BLACKLIST_USERS=
|
- BLACKLIST_USERS=
|
||||||
- WHITELIST_USERS=
|
- WHITELIST_USERS=
|
||||||
- PLEX_BASEURL=
|
- PLEX_BASEURL=https://localhost:32400
|
||||||
- PLEX_TOKEN=
|
- PLEX_TOKEN=plex_token
|
||||||
- JELLYFIN_BASEURL=
|
- JELLYFIN_BASEURL=http://localhost:8096
|
||||||
- JELLYFIN_TOKEN=
|
- JELLYFIN_TOKEN=jelly_token
|
||||||
- SSL_BYPASS=True
|
- SSL_BYPASS=True
|
||||||
- SYNC_FROM_PLEX_TO_JELLYFIN=True
|
- SYNC_FROM_PLEX_TO_JELLYFIN=True
|
||||||
- SYNC_FROM_JELLYFIN_TO_PLEX=True
|
- SYNC_FROM_JELLYFIN_TO_PLEX=True
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
PlexAPI==4.15.2
|
PlexAPI==4.15.5
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
python-dotenv==1.0.0
|
python-dotenv==1.0.0
|
||||||
aiohttp==3.8.5
|
aiohttp==3.8.6
|
||||||
|
|||||||
@@ -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("MARKFILE", "mark.log")
|
||||||
|
|
||||||
|
|
||||||
def logger(message: str, log_type=0):
|
def logger(message: str, log_type=0):
|
||||||
@@ -22,6 +23,10 @@ def logger(message: str, log_type=0):
|
|||||||
output = f"[DEBUG]: {output}"
|
output = f"[DEBUG]: {output}"
|
||||||
elif log_type == 4:
|
elif log_type == 4:
|
||||||
output = f"[WARNING]: {output}"
|
output = f"[WARNING]: {output}"
|
||||||
|
elif log_type == 5:
|
||||||
|
output = f"[MARK]: {output}"
|
||||||
|
elif log_type == 6:
|
||||||
|
output = f"[DRYRUN]: {output}"
|
||||||
else:
|
else:
|
||||||
output = None
|
output = None
|
||||||
|
|
||||||
@@ -31,6 +36,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:
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -95,7 +100,7 @@ class Jellyfin:
|
|||||||
return await self.query(query, query_type, session, identifiers)
|
return await self.query(query, query_type, session, identifiers)
|
||||||
|
|
||||||
results = None
|
results = None
|
||||||
headers = {"Accept": "application/json", "X-Emby-Token": self.token}
|
|
||||||
authorization = (
|
authorization = (
|
||||||
"MediaBrowser , "
|
"MediaBrowser , "
|
||||||
'Client="other", '
|
'Client="other", '
|
||||||
@@ -103,7 +108,7 @@ class Jellyfin:
|
|||||||
'DeviceId="script", '
|
'DeviceId="script", '
|
||||||
'Version="0.0.0"'
|
'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":
|
if query_type == "get":
|
||||||
async with session.get(
|
async with session.get(
|
||||||
@@ -632,25 +637,39 @@ class Jellyfin:
|
|||||||
if movie_status:
|
if movie_status:
|
||||||
jellyfin_video_id = jellyfin_video["Id"]
|
jellyfin_video_id = jellyfin_video["Id"]
|
||||||
if movie_status["completed"]:
|
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:
|
if not dryrun:
|
||||||
logger(f"Marking {msg}", 0)
|
logger(msg, 5)
|
||||||
await self.query(
|
await self.query(
|
||||||
f"/Users/{user_id}/PlayedItems/{jellyfin_video_id}",
|
f"/Users/{user_id}/PlayedItems/{jellyfin_video_id}",
|
||||||
"post",
|
"post",
|
||||||
session,
|
session,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger(f"Dryrun {msg}", 0)
|
logger(msg, 6)
|
||||||
|
|
||||||
|
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: {jellyfin_video.get('Name')} as partially watched for {floor(movie_status['time'] / 60_000)} minutes for {user_name} in {library}"
|
||||||
|
"""
|
||||||
if not dryrun:
|
if not dryrun:
|
||||||
pass
|
pass
|
||||||
# logger(f"Marked {msg}", 0)
|
# logger(msg, 5)
|
||||||
else:
|
else:
|
||||||
pass
|
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:
|
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}",
|
||||||
@@ -799,30 +818,46 @@ class Jellyfin:
|
|||||||
jellyfin_episode_id = jellyfin_episode["Id"]
|
jellyfin_episode_id = jellyfin_episode["Id"]
|
||||||
if episode_status["completed"]:
|
if episode_status["completed"]:
|
||||||
msg = (
|
msg = (
|
||||||
f"{jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}"
|
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} for Jellyfin"
|
+ f" as watched for {user_name} in {library}"
|
||||||
)
|
)
|
||||||
if not dryrun:
|
if not dryrun:
|
||||||
logger(f"Marked {msg}", 0)
|
logger(msg, 5)
|
||||||
await self.query(
|
await self.query(
|
||||||
f"/Users/{user_id}/PlayedItems/{jellyfin_episode_id}",
|
f"/Users/{user_id}/PlayedItems/{jellyfin_episode_id}",
|
||||||
"post",
|
"post",
|
||||||
session,
|
session,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger(f"Dryrun {msg}", 0)
|
logger(msg, 6)
|
||||||
|
|
||||||
|
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: {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}"
|
||||||
)
|
)
|
||||||
|
"""
|
||||||
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}",
|
||||||
|
|||||||
49
src/plex.py
49
src/plex.py
@@ -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,
|
||||||
@@ -295,19 +296,28 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
|
|||||||
)
|
)
|
||||||
if video_status:
|
if video_status:
|
||||||
if video_status["completed"]:
|
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:
|
if not dryrun:
|
||||||
logger(f"Marked {msg}", 0)
|
logger(msg, 5)
|
||||||
movies_search.markWatched()
|
movies_search.markWatched()
|
||||||
else:
|
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:
|
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:
|
if not dryrun:
|
||||||
logger(f"Marked {msg}", 0)
|
logger(msg, 5)
|
||||||
movies_search.updateProgress(video_status["time"])
|
movies_search.updateProgress(video_status["time"])
|
||||||
else:
|
else:
|
||||||
logger(f"Dryrun {msg}", 0)
|
logger(msg, 6)
|
||||||
|
|
||||||
|
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}",
|
||||||
@@ -326,19 +336,34 @@ def update_user_watched(user, user_plex, library, videos, dryrun):
|
|||||||
)
|
)
|
||||||
if video_status:
|
if video_status:
|
||||||
if video_status["completed"]:
|
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:
|
if not dryrun:
|
||||||
logger(f"Marked {msg}", 0)
|
logger(msg, 5)
|
||||||
episode_search.markWatched()
|
episode_search.markWatched()
|
||||||
else:
|
else:
|
||||||
logger(f"Dryrun {msg}", 0)
|
logger(msg, 6)
|
||||||
|
|
||||||
|
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"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:
|
if not dryrun:
|
||||||
logger(f"Marked {msg}", 0)
|
logger(msg, 5)
|
||||||
episode_search.updateProgress(video_status["time"])
|
episode_search.updateProgress(video_status["time"])
|
||||||
else:
|
else:
|
||||||
logger(f"Dryrun {msg}", 0)
|
logger(msg, 6)
|
||||||
|
|
||||||
|
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}",
|
||||||
|
|||||||
Reference in New Issue
Block a user