mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-26 18:55:44 +02:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
12
.github/workflows/build-push-backend.yml
vendored
12
.github/workflows/build-push-backend.yml
vendored
@@ -94,6 +94,16 @@ jobs:
|
|||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}}
|
||||||
type=sha
|
type=sha
|
||||||
|
|
||||||
|
- name: Extract version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/}
|
||||||
|
else
|
||||||
|
VERSION="dev-${GITHUB_SHA::7}"
|
||||||
|
fi
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
@@ -104,4 +114,4 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
build-args: |
|
build-args: |
|
||||||
VERSION=${{ steps.meta.outputs.version }}
|
VERSION=${{ steps.version.outputs.version }}
|
||||||
|
|||||||
6
.github/workflows/build-push-frontend.yml
vendored
6
.github/workflows/build-push-frontend.yml
vendored
@@ -26,8 +26,10 @@ jobs:
|
|||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: './web/package-lock.json'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install
|
run: npm ci
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
- name: Lint code
|
- name: Lint code
|
||||||
run: npm run lint
|
run: npm run lint
|
||||||
@@ -91,3 +93,5 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
build-args: |
|
build-args: |
|
||||||
VERSION=${{ steps.version.outputs.version }}
|
VERSION=${{ steps.version.outputs.version }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|||||||
37
Dockerfile
37
Dockerfile
@@ -1,23 +1,42 @@
|
|||||||
|
FROM ghcr.io/astral-sh/uv:debian-slim AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends ca-certificates gcc python3-dev && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
|
||||||
|
RUN uv sync --locked
|
||||||
|
|
||||||
FROM ghcr.io/astral-sh/uv:debian-slim
|
FROM ghcr.io/astral-sh/uv:debian-slim
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
LABEL version=${VERSION}
|
LABEL version=${VERSION}
|
||||||
LABEL description="Docker image for the backend of MediaManager"
|
LABEL description="Docker image for the backend of MediaManager"
|
||||||
|
|
||||||
ENV IMAGE_DIRECTORY=/data/images
|
ENV IMAGE_DIRECTORY=/data/images \
|
||||||
ENV TV_SHOW_DIRECTORY=/data/tv
|
TV_SHOW_DIRECTORY=/data/tv \
|
||||||
ENV MOVIE_DIRECTORY=/data/movies
|
MOVIE_DIRECTORY=/data/movies \
|
||||||
ENV TORRENT_DIRECTORY=/data/torrents
|
TORRENT_DIRECTORY=/data/torrents \
|
||||||
ENV OPENID_ENABLED=FALSE
|
OPENID_ENABLED=FALSE \
|
||||||
|
PUBLIC_VERSION=${VERSION} \
|
||||||
|
UV_PROJECT_ENVIRONMENT=/app/.venv
|
||||||
|
|
||||||
RUN apt update && apt install -y ca-certificates gcc python3-dev
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends ca-certificates && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/.venv /app/.venv
|
||||||
|
COPY --from=builder /app/pyproject.toml /app/uv.lock ./
|
||||||
|
|
||||||
COPY --chmod=755 mediamanager-backend-startup.sh .
|
COPY --chmod=755 mediamanager-backend-startup.sh .
|
||||||
COPY media_manager ./media_manager
|
COPY media_manager ./media_manager
|
||||||
COPY alembic ./alembic
|
COPY alembic ./alembic
|
||||||
COPY alembic.ini .
|
COPY alembic.ini .
|
||||||
COPY pyproject.toml .
|
|
||||||
COPY uv.lock .
|
|
||||||
RUN uv sync --locked
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
CMD ["/app/mediamanager-backend-startup.sh"]
|
CMD ["/app/mediamanager-backend-startup.sh"]
|
||||||
@@ -54,11 +54,14 @@ other services.
|
|||||||
- [x] create separate metadata relay service, so that api keys for TMDB and TVDB are not strictly needed
|
- [x] create separate metadata relay service, so that api keys for TMDB and TVDB are not strictly needed
|
||||||
- [x] support for movies
|
- [x] support for movies
|
||||||
- [x] expand README with more information and a quickstart guide
|
- [x] expand README with more information and a quickstart guide
|
||||||
|
- [x] improve reliability of scheduled tasks
|
||||||
- [ ] add notification system
|
- [ ] add notification system
|
||||||
- [ ] add in-depth documentation on the architecture of the codebase
|
- [ ] add in-depth documentation on the architecture of the codebase
|
||||||
- [ ] make indexer module multithreaded
|
- [ ] make indexer module multithreaded
|
||||||
- [ ] add support for deluge and transmission
|
- [ ] add support for deluge and transmission
|
||||||
- [ ] improve reliability of scheduled tasks
|
- [ ] add delete button for movies/TV shows
|
||||||
|
- [ ] rework prowlarr module (select which indexers to use, etc.)
|
||||||
|
- [ ] add sequence diagrams to the documentation
|
||||||
- [ ] _maybe_ rework the logo
|
- [ ] _maybe_ rework the logo
|
||||||
- [ ] _maybe_ add support for configuration via toml config file
|
- [ ] _maybe_ add support for configuration via toml config file
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ weekly_trigger = CronTrigger(
|
|||||||
day_of_week="mon", hour=0, minute=0, jitter=60 * 60 * 24 * 2
|
day_of_week="mon", hour=0, minute=0, jitter=60 * 60 * 24 * 2
|
||||||
)
|
)
|
||||||
scheduler.add_job(hourly_tasks, trigger)
|
scheduler.add_job(hourly_tasks, trigger)
|
||||||
scheduler.add_job(weekly_tasks, trigger)
|
scheduler.add_job(weekly_tasks, weekly_trigger)
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
|
|
||||||
|
|
||||||
@@ -288,5 +288,13 @@ except Exception as e:
|
|||||||
log.error(f"Error creating test directory: {e}")
|
log.error(f"Error creating test directory: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def hello_world() -> dict:
|
||||||
|
"""
|
||||||
|
A simple endpoint to check if the API is running.
|
||||||
|
"""
|
||||||
|
return {"message": "Hello World!", "version": os.getenv("PUBLIC_VERSION")}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run(app, host="127.0.0.1", port=5049, log_config=LOGGING_CONFIG)
|
uvicorn.run(app, host="127.0.0.1", port=5049, log_config=LOGGING_CONFIG)
|
||||||
|
|||||||
@@ -241,10 +241,13 @@ def get_all_available_torrents_for_a_movie(
|
|||||||
def download_torrent_for_movie(
|
def download_torrent_for_movie(
|
||||||
movie_service: movie_service_dep,
|
movie_service: movie_service_dep,
|
||||||
movie_id: MovieId,
|
movie_id: MovieId,
|
||||||
indexer_result_id: IndexerQueryResultId,
|
public_indexer_result_id: IndexerQueryResultId,
|
||||||
|
override_file_path_suffix: str = "",
|
||||||
):
|
):
|
||||||
return movie_service.download_torrent(
|
return movie_service.download_torrent(
|
||||||
public_indexer_result_id=indexer_result_id, movie_id=movie_id
|
public_indexer_result_id=public_indexer_result_id,
|
||||||
|
movie_id=movie_id,
|
||||||
|
override_movie_file_path_suffix=override_file_path_suffix,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# This script is used to start the MediaManager backend service.
|
# This script is used to start the MediaManager backend service.
|
||||||
|
|
||||||
|
|
||||||
|
# text created with https://patorjk.com/software/taag/ font: Slanted
|
||||||
|
echo "
|
||||||
|
__ ___ ___ __ ___ ____ __ __
|
||||||
|
/ |/ /__ ____/ (_)___ _/ |/ /___ _____ ____ _____ ____ _____ / __ )____ ______/ /_____ ____ ____/ /
|
||||||
|
/ /|_/ / _ \/ __ / / __ \`/ /|_/ / __ \`/ __ \/ __ \`/ __ \`/ _ \/ ___/ / __ / __ \`/ ___/ //_/ _ \/ __ \/ __ /
|
||||||
|
/ / / / __/ /_/ / / /_/ / / / / /_/ / / / / /_/ / /_/ / __/ / / /_/ / /_/ / /__/ ,< / __/ / / / /_/ /
|
||||||
|
/_/ /_/\___/\__,_/_/\__,_/_/ /_/\__,_/_/ /_/\__,_/\__, /\___/_/ /_____/\__,_/\___/_/|_|\___/_/ /_/\__,_/
|
||||||
|
/____/
|
||||||
|
"
|
||||||
|
echo "Buy me a coffee at https://buymeacoffee.com/maxdorninger"
|
||||||
|
echo "Running DB migrations..."
|
||||||
|
|
||||||
uv run alembic upgrade head
|
uv run alembic upgrade head
|
||||||
uv run fastapi run /app/media_manager/main.py
|
|
||||||
|
echo "Starting MediaManager backend service..."
|
||||||
|
uv run fastapi run /app/media_manager/main.py --port 8000
|
||||||
|
|||||||
@@ -1,28 +1,39 @@
|
|||||||
ARG VERSION
|
ARG VERSION
|
||||||
ARG BASE_URL=""
|
ARG BASE_URL=""
|
||||||
FROM node:24-alpine AS build
|
FROM node:24-alpine AS build
|
||||||
USER node:node
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
ARG VERSION
|
||||||
|
ARG BASE_URL
|
||||||
|
|
||||||
COPY --chown=node:node . .
|
# Copy package files first for better layer caching
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci && npm cache clean --force
|
||||||
|
|
||||||
RUN npm ci
|
# Copy source code after dependencies are installed
|
||||||
|
COPY . .
|
||||||
RUN env PUBLIC_VERSION=${VERSION} BASE_URL=${BASE_URL} npm run build
|
RUN env PUBLIC_VERSION=${VERSION} BASE_URL=${BASE_URL} npm run build
|
||||||
|
|
||||||
FROM node:24-alpine AS frontend
|
FROM node:24-alpine AS frontend
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
USER node:node
|
|
||||||
|
USER node
|
||||||
|
EXPOSE 3000
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
LABEL version=${VERSION}
|
LABEL version=${VERSION}
|
||||||
LABEL description="Docker image for the web frontend of MediaManager"
|
LABEL description="Docker image for the web frontend of MediaManager"
|
||||||
|
|
||||||
|
|
||||||
ENV PUBLIC_VERSION=${VERSION}
|
ENV PUBLIC_VERSION=${VERSION}
|
||||||
ENV PUBLIC_SSR_WEB=false
|
ENV PUBLIC_SSR_WEB=false
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --chown=node:node package*.json ./
|
# Copy built application and package files
|
||||||
COPY --chown=node:node --from=build /app/node_modules ./node_modules/
|
COPY --from=build /app/build ./build
|
||||||
COPY --chown=node:node --from=build /app/build/ ./build/
|
COPY --from=build /app/package*.json ./
|
||||||
|
COPY --chmod=755 entrypoint.sh .
|
||||||
|
|
||||||
EXPOSE 3000
|
# Install only production dependencies needed for the Node adapter
|
||||||
|
RUN npm ci --only=production && npm cache clean --force
|
||||||
|
|
||||||
|
CMD ["/app/entrypoint.sh"]
|
||||||
|
|
||||||
CMD ["node","build/index.js"]
|
|
||||||
|
|||||||
16
web/entrypoint.sh
Normal file
16
web/entrypoint.sh
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# This script is used to start the MediaManager frontend service.
|
||||||
|
|
||||||
|
|
||||||
|
# text created with https://patorjk.com/software/taag/ font: Slanted
|
||||||
|
cat << EOF
|
||||||
|
__ ___ ___ __ ___ ______ __ __
|
||||||
|
/ |/ /__ ____/ (_)___ _/ |/ /___ _____ ____ _____ ____ _____ / ____/________ ____ / /____ ____ ____/ /
|
||||||
|
/ /|_/ / _ \/ __ / / __ \`/ /|_/ / __ \`/ __ \/ __ \`/ __ \`/ _ \/ ___/ / /_ / ___/ __ \/ __ \/ __/ _ \/ __ \/ __ /
|
||||||
|
/ / / / __/ /_/ / / /_/ / / / / /_/ / / / / /_/ / /_/ / __/ / / __/ / / / /_/ / / / / /_/ __/ / / / /_/ /
|
||||||
|
/_/ /_/\___/\__,_/_/\__,_/_/ /_/\__,_/_/ /_/\__,_/\__, /\___/_/ /_/ /_/ \____/_/ /_/\__/\___/_/ /_/\__,_/
|
||||||
|
/____/
|
||||||
|
EOF
|
||||||
|
echo "Buy me a coffee at https://buymeacoffee.com/maxdorninger"
|
||||||
|
echo "Starting MediaManager frontend service..."
|
||||||
|
node build/index.js
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
<img class="size-12" src={logo} alt="Media Manager Logo" />
|
<img class="size-12" src={logo} alt="Media Manager Logo" />
|
||||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||||
<span class="truncate font-semibold">Media Manager</span>
|
<span class="truncate font-semibold">Media Manager</span>
|
||||||
<span class="truncate text-xs">v{PUBLIC_VERSION}</span>
|
<span class="truncate text-xs">{PUBLIC_VERSION}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
let url = new URL(apiUrl + `/movies/${movie.id}/torrents`);
|
let url = new URL(apiUrl + `/movies/${movie.id}/torrents`);
|
||||||
url.searchParams.append('public_indexer_result_id', result_id);
|
url.searchParams.append('public_indexer_result_id', result_id);
|
||||||
if (filePathSuffix !== '') {
|
if (filePathSuffix !== '') {
|
||||||
url.searchParams.append('file_path_suffix', filePathSuffix);
|
url.searchParams.append('override_file_path_suffix', filePathSuffix);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
|
|||||||
Reference in New Issue
Block a user