Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fc6d792bc | ||
|
|
c9f1a2d93a | ||
|
|
bbdd11d1b5 | ||
|
|
1827908936 | ||
|
|
8b99a744e2 | ||
|
|
2d42b60e26 | ||
|
|
448dd12fa5 | ||
|
|
a30a554e06 | ||
|
|
bd6918abd1 | ||
|
|
9a0b0443d4 | ||
| 1726b21d1d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -24,3 +24,6 @@ phpstan.neon
|
|||||||
/phpunit.xml
|
/phpunit.xml
|
||||||
/.phpunit.cache/
|
/.phpunit.cache/
|
||||||
###< phpunit/phpunit ###
|
###< phpunit/phpunit ###
|
||||||
|
|
||||||
|
docs/examples/movies/
|
||||||
|
docs/examples/tvshows/
|
||||||
|
|||||||
224
README.md
224
README.md
@@ -4,28 +4,6 @@ and download your favorite movies and tv shows. You can think of it like Stremio
|
|||||||
comparison to Stremio? That's because Torsearch uses the same source for media files that Stremio uses: Torrentio
|
comparison to Stremio? That's because Torsearch uses the same source for media files that Stremio uses: Torrentio
|
||||||
(hence the name: Torsearch).
|
(hence the name: Torsearch).
|
||||||
|
|
||||||
After two failed attempts at running a media server, I decided to hang up my hat and give up my dream of a self-hosted
|
|
||||||
media server. I figured the days of torrenting were mostly over and everybody ranting & raving about their media collections
|
|
||||||
must be going to Walmart and buying up the bucket of old movies they have. That's until I stumbled across Stremio.
|
|
||||||
|
|
||||||
At first, it seemed too good to be true, but I was yearning for something just sketchy enough to try out. What could
|
|
||||||
go wrong with handing over my card information to an unknown organization across the pond? At the end of the day,
|
|
||||||
the cost benefit analysis landed in my favor, and about 30 minutes after purchasing my Real Debrid subscription and
|
|
||||||
setting up Stremio, I was in business.
|
|
||||||
|
|
||||||
My mind was blown. I might not have the most "cultured" taste in media, but it had everything I searched for and more! After
|
|
||||||
watching a few movies, I noticed the "Copy Download Link" button. "What's this lil guy do?" I asked myself. Duh, it
|
|
||||||
downloads the f*****g movie. And there's the 💡flashing over my head. There's gotta be a way to automate this, I told myself.
|
|
||||||
|
|
||||||
After a month of studying Stremio's code and lots of tinkering, I finally figured it out. Torrentio is the magic behind
|
|
||||||
the scenes. You feed it a Real Debrid API key and an IMDB ID, and it gives you a list of results to download that media.
|
|
||||||
Easy peasy.
|
|
||||||
|
|
||||||
In about an hour I had a proof of concept working. It wasn't pretty, but it wasn't supposed to be. That proof-of-concept
|
|
||||||
has blossomed into the beautiful Torsearch that I've been using nearly every day since then. The code in this repo
|
|
||||||
is a complete re-write of the proof-of-concept that started out ugly and ended up even uglier. Knowing the core functionality
|
|
||||||
required to make it work, I was able to re-write the app with some design patterns in place.
|
|
||||||
|
|
||||||
## Pics or didn't happen
|
## Pics or didn't happen
|
||||||

|

|
||||||

|

|
||||||
@@ -37,14 +15,202 @@ required to make it work, I was able to re-write the app with some design patter
|
|||||||
- Search for Movies & TV Shows by their name
|
- Search for Movies & TV Shows by their name
|
||||||
- Download directly to your NAS
|
- Download directly to your NAS
|
||||||
- Monitor TV Shows for new episodes and automatically download them
|
- Monitor TV Shows for new episodes and automatically download them
|
||||||
- Browse popular media and view its download options
|
- Discover new media
|
||||||
- LDAP or local auth (OIDC coming soon)
|
- OIDC
|
||||||
|
|
||||||
## Features on the roadmap
|
|
||||||
- Requests - allow users to request new media
|
|
||||||
- OIDC auth
|
|
||||||
- Prometheus logging
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
1. Clone the repo
|
For all pieces to work, you will need to serve the application over HTTPS. Running behind an SSL terminating
|
||||||
|
reverse proxy is the recommended approach.
|
||||||
|
|
||||||
|
1. Create a `compose.yml` file
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
### The app contains the application and web server ###
|
||||||
|
app:
|
||||||
|
image: code.caldwell.digital/home/torsearch-app:${TAG}
|
||||||
|
ports:
|
||||||
|
- "${WEB_PORT}:80"
|
||||||
|
env_file: .env
|
||||||
|
depends_on:
|
||||||
|
database:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- ${LOCAL_MOVIES_DIR}:/var/download/movies
|
||||||
|
- ${LOCAL_TVSHOWS_DIR}:/var/download/tvshows
|
||||||
|
- mercure_data:/data
|
||||||
|
- mercure_config:/config
|
||||||
|
|
||||||
|
|
||||||
|
### The worker handles downloads and async jobs ###
|
||||||
|
worker:
|
||||||
|
image: code.caldwell.digital/home/torsearch-worker:${TAG}
|
||||||
|
volumes:
|
||||||
|
- ${LOCAL_MOVIES_DIR}:/var/download/movies
|
||||||
|
- ${LOCAL_TVSHOWS_DIR}:/var/download/tvshows
|
||||||
|
env_file: .env
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
|
||||||
|
### The scheduler processes monitored media ###
|
||||||
|
scheduler:
|
||||||
|
image: code.caldwell.digital/home/torsearch-scheduler:${TAG}
|
||||||
|
volumes:
|
||||||
|
- ${LOCAL_MOVIES_DIR}:/var/download/movies
|
||||||
|
- ${LOCAL_TVSHOWS_DIR}:/var/download/tvshows
|
||||||
|
env_file: .env
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
|
||||||
|
#!! If using your own database, this can be omitted !!#
|
||||||
|
database:
|
||||||
|
image: mariadb:10.11.2
|
||||||
|
volumes:
|
||||||
|
- mysql:/var/lib/mysql
|
||||||
|
env_file: .env
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
|
||||||
|
#!! If using your own redis, this can be omitted !!#
|
||||||
|
redis:
|
||||||
|
image: redis:latest
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
command: redis-server --maxmemory 512MB
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql:
|
||||||
|
mercure_config:
|
||||||
|
mercure_data:
|
||||||
|
redis_data:
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a `.env` file
|
||||||
|
```dotenv
|
||||||
|
###################
|
||||||
|
# Torsearch #
|
||||||
|
###################
|
||||||
|
# The version of Torsearch to run. Docker will this tag.
|
||||||
|
TAG=latest
|
||||||
|
|
||||||
|
# The port for which the web server (app container) will
|
||||||
|
# serve the application on the host.
|
||||||
|
WEB_PORT=8004
|
||||||
|
|
||||||
|
# The host directories where your media is stored.
|
||||||
|
# If you would like to use a docker driver for a network
|
||||||
|
# share, update the compose.yml file to reflect that.
|
||||||
|
# These are passed into the compose file as bind mounts.
|
||||||
|
LOCAL_MOVIES_DIR="./movies"
|
||||||
|
LOCAL_TVSHOWS_DIR="./tvshows"
|
||||||
|
|
||||||
|
# Set the timezone you're in. This helps render monitored items correctly on the calendar
|
||||||
|
TZ=America/Chicago
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Symfony #
|
||||||
|
###################
|
||||||
|
# The external URL of the application where it can be reached by a browser. Should start with https://
|
||||||
|
APP_URL="<enter url>"
|
||||||
|
# Requried by Symfony Framework. Feel free to change.
|
||||||
|
APP_SECRET="70169beadfbc8101c393cbfbba27a313"
|
||||||
|
# Change to 'dev' to show logs in the browser.
|
||||||
|
APP_ENV=prod
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Mercure #
|
||||||
|
###################
|
||||||
|
# Mercure is a Caddy module built into the webserver
|
||||||
|
# that facilitates the usage of websockets to transmit
|
||||||
|
# real time data (download progress, etc.)
|
||||||
|
# TBH, I've only run into issues when changing these. If
|
||||||
|
# you have problems after changing them, just revert them.
|
||||||
|
MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
|
||||||
|
MERCURE_PUBLISHER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
||||||
|
MERCURE_SUBSCRIBER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Database #
|
||||||
|
###################
|
||||||
|
# Use the DATABASE_URL below to use the MariaDB container
|
||||||
|
# provided in the example.compose.yml file, or remove this
|
||||||
|
# line and fill in the details of your own MySQL/MariaDB server
|
||||||
|
MYSQL_USER=app
|
||||||
|
MYSQL_PASSWORD="P@ssword123"
|
||||||
|
MYSQL_DATABASE=app
|
||||||
|
MYSQL_HOST=database
|
||||||
|
MYSQL_RANDOM_ROOT_PASSWORD=true
|
||||||
|
DATABASE_URL="mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:3306/${MYSQL_DATABASE}?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Real Debrid #
|
||||||
|
###################
|
||||||
|
# Enter your Real Debrid API key which is passed to Torrentio to retrieve download options
|
||||||
|
REAL_DEBRID_KEY="<enter real debrid api key>"
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Redis #
|
||||||
|
###################
|
||||||
|
# Use your own Redis instance or use the below value to use the
|
||||||
|
# container included in the example compose.yml file.
|
||||||
|
REDIS_HOST="redis://redis"
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Auth #
|
||||||
|
###################
|
||||||
|
# Options: form_login, oidc, or ldap (experimental)
|
||||||
|
# Fill the rest of the configuration based on your choice here
|
||||||
|
# No additional config is required for form_login
|
||||||
|
AUTH_METHOD=form_login
|
||||||
|
|
||||||
|
|
||||||
|
### OIDC ###
|
||||||
|
# To use OIDC, set the AUTH_METHOD to oidc and fill in the following properties
|
||||||
|
#OIDC_WELL_KNOWN_URL=
|
||||||
|
#OIDC_CLIENT_ID=
|
||||||
|
#OIDC_CLIENT_SECRET=
|
||||||
|
# Allows you to skip the login page and directly rely on your IdP for auth.
|
||||||
|
#OIDC_BYPASS_FORM_LOGIN=
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Enter the `APP_URL` in the .env file
|
||||||
|
4. Enter the `REAL_DEBRID_KEY` in the .env file
|
||||||
|
5. Enter a new `WEB_PORT` if the default doesn't work for you
|
||||||
|
4. Run `docker compose up -d`
|
||||||
|
4. Visit the app in the browser
|
||||||
|
5. Create a user
|
||||||
|
6. Visit the Preferences page to set your filter. This filter is used whenever you don't choose a specific file to
|
||||||
|
download (e.g. downloading via Monitor or clicking the "Download Season", "Download Selected", or "Download Episode" buttons).
|
||||||
|
7. Start downloading media!
|
||||||
|
|
||||||
|
## Having issues?
|
||||||
|
Submit an issue in the repo, and I'll try to address it as soon as possible. I do have a full-time job and family, so my
|
||||||
|
time is limited, but I'll do my best!
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
This is my first contribution to open-source, the community that's given me so much over the years!
|
||||||
|
This project has been my personal hobby project for the last 1.5 years. I've written and re-written it several times.
|
||||||
|
It's been my testing ground for trying new things, so if the code looks like shit, my bad. I'm a PHP developer by day and
|
||||||
|
tinkerer by night - this was my first go with Symfony/Twig components, tailwind, the Symfony RICH bundle, and a lot more.
|
||||||
|
At some point, I'll put together a contribution guide, so others can hack on it too.
|
||||||
|
|
||||||
|
No AI was used for development (only to generate a list of countries with their flag emojis). If the code is bad, it's my fault.
|
||||||
|
|
||||||
|
# Disclaimer
|
||||||
|
Torsearch does not host any media; it only combines API results from multiple sources to make browsing them easier.
|
||||||
|
Torsearch is not affiliated with Real Debrid, Torrentio, or TMDB.
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# This file is used for local development
|
||||||
|
# see the docs/examples directory for production examples
|
||||||
services:
|
services:
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2.9.1
|
image: caddy:2.9.1
|
||||||
@@ -44,6 +46,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
TZ: America/Chicago
|
TZ: America/Chicago
|
||||||
|
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
build:
|
build:
|
||||||
dockerfile: docker/Dockerfile.scheduler
|
dockerfile: docker/Dockerfile.scheduler
|
||||||
@@ -77,9 +80,9 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
TZ: America/Chicago
|
TZ: America/Chicago
|
||||||
MYSQL_DATABASE: app
|
MYSQL_DATABASE: app
|
||||||
MYSQL_USERNAME: app
|
MYSQL_USER: app
|
||||||
MYSQL_PASSWORD: password
|
MYSQL_PASSWORD: password
|
||||||
MYSQL_ROOT_PASSWORD: password
|
MYSQL_RANDOM_ROOT_PASSWORD: true
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
services:
|
|
||||||
app:
|
|
||||||
image: registry.caldwell.digital/home/torsearch-app:${TAG}
|
|
||||||
ports:
|
|
||||||
- "${SWARM_PORT}:80"
|
|
||||||
environment:
|
|
||||||
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
|
||||||
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
|
||||||
deploy:
|
|
||||||
replicas: 2
|
|
||||||
volumes:
|
|
||||||
- /mnt/media/downloads/movies:/var/download/movies
|
|
||||||
- /mnt/media/downloads/tvshows:/var/download/tvshows
|
|
||||||
- mercure_data:/data
|
|
||||||
- mercure_config:/config
|
|
||||||
|
|
||||||
|
|
||||||
worker:
|
|
||||||
image: registry.caldwell.digital/home/torsearch-worker:${TAG}
|
|
||||||
volumes:
|
|
||||||
- /mnt/media/downloads/movies:/var/download/movies
|
|
||||||
- /mnt/media/downloads/tvshows:/var/download/tvshows
|
|
||||||
deploy:
|
|
||||||
replicas: 2
|
|
||||||
depends_on:
|
|
||||||
- app
|
|
||||||
|
|
||||||
|
|
||||||
scheduler:
|
|
||||||
image: registry.caldwell.digital/home/torsearch-scheduler:${TAG}
|
|
||||||
volumes:
|
|
||||||
- /mnt/media/downloads/movies:/var/download/movies
|
|
||||||
- /mnt/media/downloads/tvshows:/var/download/tvshows
|
|
||||||
depends_on:
|
|
||||||
- app
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
mercure_config:
|
|
||||||
mercure_data:
|
|
||||||
@@ -3,6 +3,9 @@ FROM code.caldwell.digital/home/torsearch-base:php8.4
|
|||||||
ARG APP_VERSION="0.0.0-dev"
|
ARG APP_VERSION="0.0.0-dev"
|
||||||
ENV APP_VERSION="${APP_VERSION}"
|
ENV APP_VERSION="${APP_VERSION}"
|
||||||
|
|
||||||
|
ARG TMDB_API=""
|
||||||
|
ENV TMDB_API="${TMDB_API}"
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
COPY --chmod=775 docker/app/entrypoint.sh /usr/local/bin/docker-entrypoint
|
COPY --chmod=775 docker/app/entrypoint.sh /usr/local/bin/docker-entrypoint
|
||||||
COPY docker/app/Caddyfile /etc/frankenphp/Caddyfile
|
COPY docker/app/Caddyfile /etc/frankenphp/Caddyfile
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ FROM code.caldwell.digital/home/torsearch-base-worker-supervisord:latest
|
|||||||
# Set the APP_VERSION in the image
|
# Set the APP_VERSION in the image
|
||||||
ENV APP_VERSION=${APP_VERSION}
|
ENV APP_VERSION=${APP_VERSION}
|
||||||
|
|
||||||
|
ARG TMDB_API=""
|
||||||
|
ENV TMDB_API="${TMDB_API}"
|
||||||
|
|
||||||
# Copy the actual application code from the previously built app
|
# Copy the actual application code from the previously built app
|
||||||
COPY --chown=1000:1000 --from=app_image /app /app
|
COPY --chown=1000:1000 --from=app_image /app /app
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ FROM code.caldwell.digital/home/torsearch-base-worker-supervisord:latest
|
|||||||
# Set the APP_VERSION in the image
|
# Set the APP_VERSION in the image
|
||||||
ENV APP_VERSION=${APP_VERSION}
|
ENV APP_VERSION=${APP_VERSION}
|
||||||
|
|
||||||
|
ARG TMDB_API=""
|
||||||
|
ENV TMDB_API="${TMDB_API}"
|
||||||
|
|
||||||
# Copy the actual application code from the previously built app
|
# Copy the actual application code from the previously built app
|
||||||
COPY --chown=1000:1000 --from=app_image /app /app
|
COPY --chown=1000:1000 --from=app_image /app /app
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Torsearch #
|
# Torsearch #
|
||||||
###################
|
###################
|
||||||
# The version of Torsearch to run. Docker will this tag.
|
# The version of Torsearch to run. Docker will this tag.
|
||||||
TAG=0.38.0
|
TAG=latest
|
||||||
|
|
||||||
# The port for which the web server (app container) will
|
# The port for which the web server (app container) will
|
||||||
# serve the application on the host.
|
# serve the application on the host.
|
||||||
@@ -11,8 +11,8 @@ WEB_PORT=8004
|
|||||||
# The host directories where your media is stored.
|
# The host directories where your media is stored.
|
||||||
# If you would like to use a docker driver for a network
|
# If you would like to use a docker driver for a network
|
||||||
# share, update the compose.yml file to reflect that.
|
# share, update the compose.yml file to reflect that.
|
||||||
LOCAL_MOVIES_DIR="<enter movies dir>"
|
LOCAL_MOVIES_DIR="./movies"
|
||||||
LOCAL_TVSHOWS_DIR="<enter tvshows dir>"
|
LOCAL_TVSHOWS_DIR="./tvshows"
|
||||||
|
|
||||||
# Set the timezone you're in. This helps render monitored items correctly on the calendar
|
# Set the timezone you're in. This helps render monitored items correctly on the calendar
|
||||||
TZ=America/Chicago
|
TZ=America/Chicago
|
||||||
@@ -34,6 +34,8 @@ APP_ENV=prod
|
|||||||
# Mercure is a Caddy module built into the webserver
|
# Mercure is a Caddy module built into the webserver
|
||||||
# that facilitates the usage of websockets to transmit
|
# that facilitates the usage of websockets to transmit
|
||||||
# real time data (download progress, etc.)
|
# real time data (download progress, etc.)
|
||||||
|
# TBH, I've only run into issues when changing these. If
|
||||||
|
# you have problems after changing them, just revert them.
|
||||||
MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
|
MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
|
||||||
MERCURE_PUBLISHER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
MERCURE_PUBLISHER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
||||||
MERCURE_SUBSCRIBER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
MERCURE_SUBSCRIBER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
||||||
@@ -45,11 +47,11 @@ MERCURE_SUBSCRIBER_JWT_KEY="!ChangeThisMercureHubJWTSecretKey!"
|
|||||||
# Use the DATABASE_URL below to use the MariaDB container
|
# Use the DATABASE_URL below to use the MariaDB container
|
||||||
# provided in the example.compose.yml file, or remove this
|
# provided in the example.compose.yml file, or remove this
|
||||||
# line and fill in the details of your own MySQL/MariaDB server
|
# line and fill in the details of your own MySQL/MariaDB server
|
||||||
MYSQL_RANDOM_ROOT_PASSWORD=true
|
|
||||||
MYSQL_DATABASE=app
|
|
||||||
MYSQL_USER=app
|
MYSQL_USER=app
|
||||||
MYSQL_PASSWORD=password
|
MYSQL_PASSWORD="P@ssword123"
|
||||||
|
MYSQL_DATABASE=app
|
||||||
MYSQL_HOST=database
|
MYSQL_HOST=database
|
||||||
|
MYSQL_RANDOM_ROOT_PASSWORD=true
|
||||||
DATABASE_URL="mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:3306/${MYSQL_DATABASE}?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
DATABASE_URL="mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:3306/${MYSQL_DATABASE}?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
||||||
|
|
||||||
|
|
||||||
@@ -60,15 +62,6 @@ DATABASE_URL="mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@${MYSQL_HOST}:3306/${MYSQL
|
|||||||
REAL_DEBRID_KEY="<enter real debrid api key>"
|
REAL_DEBRID_KEY="<enter real debrid api key>"
|
||||||
|
|
||||||
|
|
||||||
###################
|
|
||||||
# TMDB #
|
|
||||||
###################
|
|
||||||
# Enter your TMDB API key
|
|
||||||
# This is used to provide rich search results when searching
|
|
||||||
# for media and rendering the Popular Movies and TV Shows section.
|
|
||||||
TMDB_API="<enter tmdb api key>"
|
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# Redis #
|
# Redis #
|
||||||
###################
|
###################
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ services:
|
|||||||
- "${WEB_PORT}:80"
|
- "${WEB_PORT}:80"
|
||||||
env_file: .env
|
env_file: .env
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
database:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- ${LOCAL_MOVIES_DIR}:/var/download/movies
|
- ${LOCAL_MOVIES_DIR}:/var/download/movies
|
||||||
- ${LOCAL_TVSHOWS_DIR}:/var/download/tvshows
|
- ${LOCAL_TVSHOWS_DIR}:/var/download/tvshows
|
||||||
@@ -43,7 +44,7 @@ services:
|
|||||||
- mysql:/var/lib/mysql
|
- mysql:/var/lib/mysql
|
||||||
env_file: .env
|
env_file: .env
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "mysqladmin", "-u", "${MYSQL_USER}", "-p", "${MYSQL_PASSWORD}" ,"ping", "-h", "localhost" ]
|
test: ["CMD", "mysqladmin", "ping"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|||||||
129
nomad.deploy.hcl
129
nomad.deploy.hcl
@@ -1,129 +0,0 @@
|
|||||||
variable "image_tag" {
|
|
||||||
type = string
|
|
||||||
description = "Docker image tag to deploy."
|
|
||||||
default = "latest"
|
|
||||||
}
|
|
||||||
|
|
||||||
job "torsearch" {
|
|
||||||
datacenters = [ "home" ]
|
|
||||||
type = "service"
|
|
||||||
|
|
||||||
group "app" {
|
|
||||||
count = 2
|
|
||||||
|
|
||||||
update {
|
|
||||||
max_parallel = 4
|
|
||||||
min_healthy_time = "30s"
|
|
||||||
healthy_deadline = "3m"
|
|
||||||
auto_revert = true
|
|
||||||
}
|
|
||||||
|
|
||||||
network {
|
|
||||||
port "app" {
|
|
||||||
to = 80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task "app" {
|
|
||||||
driver = "docker"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image = "registry.caldwell.digital/home/torsearch-app:${var.image_tag}"
|
|
||||||
ports = ["app"]
|
|
||||||
}
|
|
||||||
|
|
||||||
env {
|
|
||||||
MERCURE_PUBLISHER_JWT_KEY = "!ChangeThisMercureHubJWTSecretKey!"
|
|
||||||
MERCURE_SUBSCRIBER_JWT_KEY = "!ChangeThisMercureHubJWTSecretKey!"
|
|
||||||
}
|
|
||||||
|
|
||||||
service {
|
|
||||||
name = "torsearch-app"
|
|
||||||
provider = "nomad"
|
|
||||||
port = "app"
|
|
||||||
|
|
||||||
meta {
|
|
||||||
nomad_ingress_enabled = true
|
|
||||||
nomad_ingress_hostname = "torsearch-nomad.caldwell.digital"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
group "worker" {
|
|
||||||
count = 2
|
|
||||||
update {
|
|
||||||
max_parallel = 4
|
|
||||||
min_healthy_time = "30s"
|
|
||||||
healthy_deadline = "3m"
|
|
||||||
auto_revert = true
|
|
||||||
}
|
|
||||||
|
|
||||||
volume "media" {
|
|
||||||
type = "host"
|
|
||||||
source = "media"
|
|
||||||
read_only = false
|
|
||||||
}
|
|
||||||
|
|
||||||
task "worker" {
|
|
||||||
driver = "docker"
|
|
||||||
|
|
||||||
volume_mount {
|
|
||||||
volume = "media"
|
|
||||||
destination = "/var/download"
|
|
||||||
read_only = false
|
|
||||||
}
|
|
||||||
|
|
||||||
config {
|
|
||||||
image = "registry.caldwell.digital/home/torsearch-worker:${var.image_tag}"
|
|
||||||
args = [
|
|
||||||
"-vv"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
service {
|
|
||||||
name = "torsearch-worker"
|
|
||||||
provider = "nomad"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
group "scheduler" {
|
|
||||||
count = 1
|
|
||||||
|
|
||||||
update {
|
|
||||||
max_parallel = 2
|
|
||||||
min_healthy_time = "30s"
|
|
||||||
healthy_deadline = "3m"
|
|
||||||
auto_revert = true
|
|
||||||
}
|
|
||||||
|
|
||||||
volume "media" {
|
|
||||||
type = "host"
|
|
||||||
source = "media"
|
|
||||||
read_only = false
|
|
||||||
}
|
|
||||||
|
|
||||||
task "scheduler" {
|
|
||||||
driver = "docker"
|
|
||||||
|
|
||||||
volume_mount {
|
|
||||||
volume = "media"
|
|
||||||
destination = "/var/download"
|
|
||||||
read_only = false
|
|
||||||
}
|
|
||||||
|
|
||||||
config {
|
|
||||||
image = "registry.caldwell.digital/home/torsearch-scheduler:${var.image_tag}"
|
|
||||||
args = [
|
|
||||||
"-vv"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
service {
|
|
||||||
name = "torsearch-scheduler"
|
|
||||||
provider = "nomad"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,6 +20,7 @@ class RegistrationFormType extends AbstractType
|
|||||||
->add('plainPassword', PasswordType::class, [
|
->add('plainPassword', PasswordType::class, [
|
||||||
// instead of being set onto the object directly,
|
// instead of being set onto the object directly,
|
||||||
// this is read and encoded in the controller
|
// this is read and encoded in the controller
|
||||||
|
'label' => 'Password',
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'attr' => ['autocomplete' => 'new-password'],
|
'attr' => ['autocomplete' => 'new-password'],
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h2 class="px-4 py-4 text-3xl font-extrabold text-orange-500">500</h2>
|
<h2 class="px-4 py-4 text-3xl font-extrabold text-orange-500">500</h2>
|
||||||
<div class="flex flex-col bg-orange-500/50 p-4 rounded-lg gap-4 w-full md:w-[420px] border-orange-500 border-2 text-gray-50 animate-fade">
|
<div class="flex flex-col bg-orange-500/50 p-4 rounded-lg gap-4 w-full md:w-[540px] border-orange-500 border-2 text-gray-50 animate-fade">
|
||||||
<div class="flex flex-col m-0 text-center">
|
<div class="flex flex-col m-0 text-center">
|
||||||
<h3 class="text-2xl text-bold text-center text-gray-50">Oh crap!</h3>
|
<h3 class="text-2xl text-bold text-center text-gray-50">Oh crap!</h3>
|
||||||
</div>
|
</div>
|
||||||
<p class="mb-2">There are many things I'm capable of, but this ain't one of 'em!</p>
|
<p class="mb-2">There are many things I'm capable of, but this ain't one of 'em!</p>
|
||||||
<pre class="bg-gray-800 text-white p-4 rounded-md overflow-x-auto">
|
<p class="text-sm mb-1">
|
||||||
<code class="language-plaintext">
|
<code>{{ exception.file }}</code>
|
||||||
{{ exception.message }}
|
</p>
|
||||||
</code>
|
<pre class="bg-gray-800 text-white p-4 rounded-md overflow-x-auto"><code class="language-plaintext">{{ exception.message|trim }}</code></pre>
|
||||||
</pre>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<div class="flex flex-row gap-2 mb-2">
|
<div class="flex flex-row gap-2 mb-2">
|
||||||
<input type="hidden" name="movie_folder" id="movie_folder_hidden" value="0" />
|
<input type="hidden" name="movie_folder" id="movie_folder_hidden" value="0" />
|
||||||
<input type="checkbox" name="movie_folder" id="movie_folder" value="1" {{ downloadPreferences['movie_folder'].getPreferenceValue() == true ? 'checked' }} />
|
<input type="checkbox" name="movie_folder" id="movie_folder" value="1" {{ downloadPreferences['movie_folder'].getPreferenceValue() == true ? 'checked' }} />
|
||||||
<label class="text-gray-50" for="movie_folder">Store movies in a new directory?</label>
|
<label class="text-gray-50" for="movie_folder">Create a new directory for each movie?</label>
|
||||||
</div>
|
</div>
|
||||||
<button class="px-1.5 py-1 max-w-20 rounded-md bg-green-600 text-white" type="submit">Submit</button>
|
<button class="px-1.5 py-1 max-w-20 rounded-md bg-green-600 text-white" type="submit">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Reference in New Issue
Block a user