Compare commits

..

1 Commits

Author SHA1 Message Date
709dc07cf6 wip: starting point 2025-05-20 15:16:55 -05:00
23 changed files with 173 additions and 418 deletions

5
.env
View File

@@ -36,8 +36,3 @@ MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###
REDIS_HOST=redis://redis
MOVIES_PATH=/var/download/movies
TVSHOWS_PATH=/var/download/tvshows

View File

@@ -1,14 +1,10 @@
FROM dunglas/frankenphp
FROM registry.caldwell.digital/library/php:8.4-apache
ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
RUN apt-get update && \
apt-get install libldap2-dev -y && \
rm -rf /var/lib/apt/lists/* && \
docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && \
docker-php-ext-install ldap
RUN install-php-extensions \
pdo_mysql \
gd \
intl \
zip \
opcache
HEALTHCHECK --interval=3s --timeout=3s --retries=10 CMD [ "php", "/app/bin/console", "startup:status" ]
COPY ./bash/vhost.conf /etc/apache2/sites-enabled/vhost.conf
RUN rm /etc/apache2/sites-enabled/000-default.conf

View File

@@ -7,5 +7,5 @@ RUN apt-get update && \
docker-php-ext-install ldap
COPY --chown=www-data:www-data . /var/www
COPY bash/nginx.conf /etc/apache2/sites-enabled/vhost.conf
COPY ./bash/vhost.conf /etc/apache2/sites-enabled/vhost.conf
RUN rm /etc/apache2/sites-enabled/000-default.conf

View File

@@ -1,12 +1,18 @@
#!/bin/sh
#!/bin/bash
# Sleep for a second to ensure DB is awake and ready
SLEEP_TIME=$(shuf -i 2-4 -n 1)
SLEEP_TIME=$(shuf -i 2-5 -n 1)
echo "> Sleeping for ${SLEEP_TIME} seconds to wait for the database"
echo "> If there are errors after the migration runs, it's possible another container (scheduler, worker, etc.) already ran the migrations"
sleep $SLEEP_TIME
# Provision database
php /app/bin/console doctrine:migrations:migrate --no-interaction
php /app/bin/console db:seed
php /var/www/bin/console doctrine:migrations:migrate --no-interaction
php /var/www/bin/console db:seed
# Start Apache in the foreground
echo "Starting Apache..."
exec apachectl -D FOREGROUND
exec "$@"
exec docker-php-entrypoint "$@"

View File

@@ -1,32 +0,0 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
root /var/www/public;
location /hub/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://mercure/;
}
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
}

23
bash/vhost.conf Executable file
View File

@@ -0,0 +1,23 @@
<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/public
DirectoryIndex /index.php
<LocationMatch "/hub/">
ProxyPass http://mercure:80/
ProxyPassReverse http://mercure:80/
</LocationMatch>
<Directory /var/www/public>
AllowOverride None
Order Allow,Deny
Allow from All
FallbackResource /index.php
</Directory>
<Directory /var/www/public/bundles>
FallbackResource disabled
</Directory>
</VirtualHost>

View File

@@ -12,26 +12,6 @@ services:
- $PWD/bash/caddy:/etc/caddy
- $PWD/bash/certs:/etc/ssl
app:
build: .
restart: unless-stopped
environment:
FRANKENPHP_CONFIG: "worker /app/public/index.php"
volumes:
- $PWD:/app
tty: true
depends_on:
database:
condition: service_healthy
worker:
build: .
restart: unless-stopped
volumes:
- $PWD:/app
tty: true
command: php /app/bin/console messenger:consume async -vv
redis:
image: redis:latest
volumes:
@@ -39,6 +19,34 @@ services:
command: redis-server --maxmemory 512MB
restart: unless-stopped
app:
image: code.caldwell.digital/home/torsearch:0.14.5-app
volumes:
- ./:/var/www
depends_on:
database:
condition: service_healthy
worker:
image: code.caldwell.digital/home/torsearch:0.14.5-worker
volumes:
- ./:/var/www
- ./var/download:/var/download
command: php ./bin/console messenger:consume async -vvv --time-limit=3600
depends_on:
app:
condition: service_healthy
scheduler:
image: code.caldwell.digital/home/torsearch:0.14.5-worker
volumes:
- ./:/var/www
- ./var/download:/var/download
command: php ./bin/console messenger:consume scheduler_monitor -vv --time-limit=3600
depends_on:
app:
condition: service_healthy
mercure:
image: dunglas/mercure
restart: unless-stopped
@@ -70,8 +78,7 @@ services:
MYSQL_ROOT_PASSWORD: password
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
timeout: 10s
retries: 10
adminer:

View File

@@ -22,7 +22,6 @@
"p3k/emoji-detector": "^1.2",
"php-tmdb/api": "^4.1",
"predis/predis": "^2.4",
"runtime/frankenphp-symfony": "^0.2.0",
"symfony/asset": "7.2.*",
"symfony/console": "7.2.*",
"symfony/doctrine-messenger": "7.2.*",

54
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c4ad1f54b8dd44fb55097f631c945460",
"content-hash": "33f1579a34e7ada02bb4738a9b39f493",
"packages": [
{
"name": "1tomany/rich-bundle",
@@ -3300,58 +3300,6 @@
},
"time": "2021-10-29T13:26:27+00:00"
},
{
"name": "runtime/frankenphp-symfony",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/php-runtime/frankenphp-symfony.git",
"reference": "56822c3631d9522a3136a4c33082d006bdfe4bad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-runtime/frankenphp-symfony/zipball/56822c3631d9522a3136a4c33082d006bdfe4bad",
"reference": "56822c3631d9522a3136a4c33082d006bdfe4bad",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
"symfony/http-kernel": "^5.4 || ^6.0 || ^7.0",
"symfony/runtime": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Runtime\\FrankenPhpSymfony\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kévin Dunglas",
"email": "kevin@dunglas.dev"
}
],
"description": "FrankenPHP runtime for Symfony",
"support": {
"issues": "https://github.com/php-runtime/frankenphp-symfony/issues",
"source": "https://github.com/php-runtime/frankenphp-symfony/tree/0.2.0"
},
"funding": [
{
"url": "https://github.com/nyholm",
"type": "github"
}
],
"time": "2023-12-12T12:06:11+00:00"
},
{
"name": "symfony/asset",
"version": "v7.2.0",

View File

@@ -29,7 +29,6 @@ framework:
'App\Monitor\Action\Command\MonitorTvSeasonCommand': async
'App\Monitor\Action\Command\MonitorTvShowCommand': async
'App\Monitor\Action\Command\MonitorMovieCommand': async
'App\Torrentio\Action\Command\GetTvShowOptionsCommand': async
# when@test:
# framework:

View File

@@ -7,7 +7,7 @@ parameters:
# Media
media.default_movies_dir: movies
media.default_tvshows_dir: tvshows
media.movies_path: '%env(default:media.default_movies_dir:MOVIES_PATH)%'
media.movies_path: '/var/download/%env(default:media.default_movies_dir:MOVIES_PATH)%'
media.tvshows_path: '/var/download/%env(default:media.default_tvshows_dir:TVSHOWS_PATH)%'
# Mercure

View File

@@ -1,39 +1,30 @@
services:
app:
image: registry.caldwell.digital/home/torsearch-app:${TAG}
php:
image: registry.caldwell.digital/home/torsearch/app:${TAG}
ports:
- '8001:80'
- "8001:80"
deploy:
replicas: 2
depends_on:
- database
worker:
image: registry.caldwell.digital/home/torsearch-worker:${TAG}
image: registry.caldwell.digital/home/torsearch/app:${TAG}
volumes:
- /mnt/media/downloads/movies:/var/download/movies
- /mnt/media/downloads/tvshows:/var/download/tvshows
restart: always
command: -vv
- /mnt/media/downloads:/var/download
command: php ./bin/console messenger:consume async -v --time-limit=3600 --limit=10
deploy:
replicas: 4
depends_on:
- app
replicas: 2
scheduler:
image: registry.caldwell.digital/home/torsearch-scheduler:${TAG}
image: registry.caldwell.digital/home/torsearch/app:${TAG}
volumes:
- ./downloads:/var/download
restart: always
depends_on:
- app
- /mnt/media/downloads:/var/download
command: php ./bin/console messenger:consume scheduler_monitor -vv --time-limit=3600
mercure:
image: dunglas/mercure
restart: unless-stopped
ports:
- "3000:80"
environment:
SERVER_NAME: ':80'
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
@@ -46,34 +37,6 @@ services:
- mercure_data:/data
- mercure_config:/config
database:
image: mariadb:10.11.2
volumes:
- mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: app
MYSQL_USERNAME: app
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:latest
volumes:
- redis_data:/data
command: redis-server --maxmemory 512MB
restart: unless-stopped
volumes:
mysql:
mercure_config:
mercure_data:
redis_data:

View File

@@ -1,22 +1,16 @@
FROM dunglas/frankenphp
FROM registry.caldwell.digital/library/php:8.4-apache
ENV FRANKENPHP_CONFIG="worker /app/public/index.php 20"
ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
RUN apt-get update && \
apt-get install libldap2-dev -y && \
rm -rf /var/lib/apt/lists/* && \
docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && \
docker-php-ext-install ldap
RUN install-php-extensions \
pdo_mysql \
gd \
intl \
zip \
opcache
COPY --chown=www-data:www-data . /var/www
COPY --chmod=0775 ./bash/entrypoint.sh /usr/local/bin/
COPY ./bash/vhost.conf /etc/apache2/sites-enabled/vhost.conf
RUN rm /etc/apache2/sites-enabled/000-default.conf
COPY . /app
COPY --chmod=775 ./bash/entrypoint.sh /usr/local/bin/docker-entrypoint
HEALTHCHECK --interval=5s --timeout=5s --retries=5 CMD [ "php", "/var/www/bin/console", "startup:status" ]
ENTRYPOINT [ "/usr/local/bin/docker-entrypoint" ]
CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ]
HEALTHCHECK --interval=3s --timeout=3s --retries=10 CMD [ "php", "/app/bin/console", "startup:status" ]
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]

View File

@@ -1,16 +0,0 @@
FROM dunglas/frankenphp
ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
RUN install-php-extensions \
pdo_mysql \
gd \
intl \
zip \
opcache
COPY . /app
ENTRYPOINT [ "php", "/app/bin/console", "messenger:consume", "schedule_monitor" ]

View File

@@ -1,18 +1,12 @@
FROM dunglas/frankenphp:php8.4-alpine
FROM registry.caldwell.digital/library/php:8.4-apache
ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
RUN apt-get update && \
apt-get install libldap2-dev -y && \
rm -rf /var/lib/apt/lists/* && \
docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && \
docker-php-ext-install ldap
RUN install-php-extensions \
pdo_mysql \
gd \
intl \
zip \
opcache
COPY --chown=www-data:www-data . /var/www
COPY . /app
ENTRYPOINT [ "php", "/app/bin/console", "messenger:consume", "async" ]
HEALTHCHECK --interval=3s --timeout=3s --retries=10 CMD return 0
COPY ./bash/vhost.conf /etc/apache2/sites-enabled/vhost.conf
RUN rm /etc/apache2/sites-enabled/000-default.conf

View File

@@ -1,9 +0,0 @@
[program:messenger-consume]
command=php /var/www/bin/console messenger:consume async --time-limit=3600
user=nobody
numprocs=2
startsecs=0
autostart=true
autorestart=true
startretries=10
process_name=%(program_name)s_%(process_num)02d

View File

@@ -5,7 +5,6 @@
# used to generate the Mercure URL behind the scenes.
APP_URL="https://torsearch.idocode.io"
APP_SECRET="70169beadfbc8101c393cbfbba27a313"
APP_ENV=prod
# Use the DATABASE_URL below to use the MariaDB container
# provided in the example.compose.yml file, or remove this
@@ -19,17 +18,13 @@ DATABASE_URL="mysql://root:password@database:3306/app?serverVersion=10.6.19.2-Ma
# This key is never saved anywhere
# else and is passed to Torrentio
# to retrieve download options
#REAL_DEBRID_KEY=""
REAL_DEBRID_KEY=""
# Enter you 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=
REAL_DEBRID_KEY="QYYBR7OSQ4VEFKWASDEZ2B4VO67KHUJY6IWOT7HHA7ATXO7QCYDQ"
TMDB_API=eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0ZTJjYjJhOGUzOGJhNjdiNjVhOGU1NGM0ZWI1MzhmOCIsIm5iZiI6MTczNzkyNjA0NC41NjQsInN1YiI6IjY3OTZhNTljYzdiMDFiNzJjNzIzZWM5YiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.e8DbNe9qrSBC1y-ANRv-VWBAtls-ZS2r7aNCiI68mpw
TMDB_API=
MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"

View File

@@ -1,36 +1,32 @@
services:
# The "entrypoint" into the application. This reverse proxy
# proxies traffic back to their respective services. If not
# running behind a reverse proxy inject your SSL certificates
# into this container.
# This container runs the actual web app in a php:8.4-fpm
# base container.
# This container runs the actual web app in a php:8.4-apache
# base container. If not running behind a reverse proxy,
# inject your SSL certificates into this container
app:
image: code.caldwell.digital/home/torsearch-app:latest
image: code.caldwell.digital/home/torsearch:0.14.5-app
ports:
- '8006:80'
- "8006:80"
env_file:
- .env
depends_on:
database:
condition: service_healthy
# Downloads happen in this container. Replicate this
# container to run multiple downloads simultaneously.
# Downloads happen asynchronously in this container. Replicate
# this container to run multiple downloads simultaneously.
# Map your "movies" folder to /var/download/movies
# Map your "TV shows" folder to /var/download/tvshows
# Map your TV shows folder to /var/download/tvshows
# If your folders are on another machine, use an NFS volume.
# This container runs a Symfony worker process.
# See: https://symfony.com/doc/current/messenger.html
worker:
image: code.caldwell.digital/home/torsearch-worker:latest
image: code.caldwell.digital/home/torsearch:0.14.5-worker
volumes:
- /mnt/media/downloads/movies:/var/download/movies
- /mnt/media/downloads/tvshows:/var/download/tvshows
command: -vvv
- ./downloads/movies:/var/download/movies
- ./downloads/tvshows:/var/download/tvshows
command: php ./bin/console messenger:consume async -v --time-limit=3600 --limit=10
env_file:
- .env
restart: always
depends_on:
app:
condition: service_healthy
@@ -41,12 +37,12 @@ services:
# This container runs a Symfony worker process.
# See: https://symfony.com/doc/current/messenger.html
scheduler:
image: code.caldwell.digital/home/torsearch-scheduler:latest
image: code.caldwell.digital/home/torsearch:0.14.5-worker
volumes:
- ./downloads:/var/download
command: php ./bin/console messenger:consume scheduler_monitor -vv --time-limit=3600
env_file:
- .env
restart: always
depends_on:
app:
condition: service_healthy
@@ -83,8 +79,7 @@ services:
MYSQL_ROOT_PASSWORD: password
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
timeout: 10s
retries: 10
redis:

View File

@@ -1,115 +0,0 @@
services:
# The "entrypoint" into the application. This reverse proxy
# proxies traffic back to their respective services. If not
# running behind a reverse proxy inject your SSL certificates
# into this container.
# This container runs the actual web app in a php:8.4-fpm
# base container.
app:
image: code.caldwell.digital/home/torsearch-app:latest
ports:
- '8006:80'
configs:
- env_file
deploy:
replicas: 2
depends_on:
- database
# Downloads happen in this container. Replicate this
# container to run multiple downloads simultaneously.
# Map your "movies" folder to /var/download/movies
# Map your "TV shows" folder to /var/download/tvshows
# If your folders are on another machine, use an NFS volume.
# This container runs a Symfony worker process.
# See: https://symfony.com/doc/current/messenger.html
worker:
image: code.caldwell.digital/home/torsearch-worker:latest
configs:
- source: env_file
target: /app/bin/.env.local
volumes:
- /mnt/media/downloads/movies:/var/download/movies
- /mnt/media/downloads/tvshows:/var/download/tvshows
restart: always
command: -vv
deploy:
replicas: 4
depends_on:
- app
# This container handles the monitoring for new media. When new
# monitors are added, jobs are periodically dispatched to this
# container, and the desired media is searched for and downloaded.
# This container runs a Symfony worker process.
# See: https://symfony.com/doc/current/messenger.html
scheduler:
image: code.caldwell.digital/home/torsearch-scheduler:latest
configs:
- env_file
volumes:
- ./downloads:/var/download
restart: always
depends_on:
- app
# This container facilitates viewing the progress of downloads
# in realtime. It also handles sending alerts and notifications.
# The MERCURE_PUBLISHER_JWT key & MERCURE_SUBSCRIBER_JWT_KEY should
# match the MERCURE_JWT_SECRET environment variable.
mercure:
image: dunglas/mercure
restart: unless-stopped
ports:
- "3001:80"
environment:
SERVER_NAME: ':80'
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
MERCURE_EXTRA_DIRECTIVES: |
cors_origins *
anonymous
command: /usr/bin/caddy run --config /etc/caddy/dev.Caddyfile
volumes:
- mercure_data:/data
- mercure_config:/config
database:
image: mariadb:10.11.2
volumes:
- mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: app
MYSQL_USERNAME: app
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:latest
volumes:
- redis_data:/data
command: redis-server --maxmemory 512MB
restart: unless-stopped
# **Optional**
# Provides a simple method of viewing the database
adminer:
image: adminer
ports:
- "8081:8080"
volumes:
mysql:
mercure_config:
mercure_data:
redis_data:
configs:
env_file:
file: $PWD/.env

View File

@@ -6,20 +6,18 @@ use App\Search\Action\Handler\GetMediaInfoHandler;
use App\Search\Action\Handler\SearchHandler;
use App\Search\Action\Input\GetMediaInfoInput;
use App\Search\Action\Input\SearchInput;
use App\Tmdb\TmdbResult;
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
use App\Torrentio\Action\Command\GetTvShowOptionsCommand;
use Carbon\Carbon;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
final class SearchController extends AbstractController
{
public function __construct(
private SearchHandler $searchHandler,
private GetMediaInfoHandler $getMediaInfoHandler,
private MessageBusInterface $bus,
) {}
#[Route('/search', name: 'app_search', methods: ['GET'])]
@@ -38,8 +36,6 @@ final class SearchController extends AbstractController
GetMediaInfoInput $input,
): Response {
$result = $this->getMediaInfoHandler->handle($input->toCommand());
$this->warmDownloadOptionCache($result->media);
return $this->render('search/result.html.twig', [
'results' => $result,
'filter' => [
@@ -52,32 +48,4 @@ final class SearchController extends AbstractController
]
]);
}
private function warmDownloadOptionCache(TmdbResult $result)
{
if ($result->mediaType === 'tvshows') {
// dispatches a job to get the download options
// for each episode and load them in cache
foreach ($result->episodes as $season => $episodes) {
// Only do the first 2 seasons, so we reduce
// getting rate-limited by Torrentio
if ($season > 2) {
return;
}
foreach ($episodes as $episode) {
$this->bus->dispatch(new GetTvShowOptionsCommand(
tmdbId: $result->tmdbId,
imdbId: $result->imdbId,
season: $season,
episode: $episode['episode_number'],
));
}
}
} elseif ($result->mediaType === 'movies') {
$this->bus->dispatch(new GetMovieOptionsCommand(
$result->tmdbId,
$result->imdbId,
));
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Download\Action\Handler\Exception;
class RealDebridBadUrlException extends \Exception
{
public function __construct(string $type)
{
$messages = [
'file_downloading' => 'This file appears to be Real Debrid\'s "Torrent is downloading..." video.',
'file_removed' => 'This file appears to be Real Debrid\'s "File is removed..." video.',
];
parent::__construct($messages[$type]);
}
}

View File

@@ -2,8 +2,10 @@
namespace App\Download\Framework\Controller;
use App\Download\Action\Handler\Exception\RealDebridBadUrlException;
use App\Download\Action\Input\DownloadMediaInput;
use App\Download\Framework\Repository\DownloadRepository;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -18,6 +20,7 @@ class ApiController extends AbstractController
private DownloadRepository $downloadRepository,
private MessageBusInterface $bus,
private readonly HubInterface $hub,
private readonly LoggerInterface $logger,
) {}
#[Route('/api/download', name: 'api_download', methods: ['POST'])]
@@ -25,6 +28,12 @@ class ApiController extends AbstractController
Request $request,
DownloadMediaInput $input,
): Response {
try {
$this->validateUrl($input->url);
} catch (RealDebridBadUrlException $e) {
return $this->json(['error' => $e->getMessage()]);
}
$download = $this->downloadRepository->insert(
$this->getUser(),
$input->url,
@@ -56,4 +65,22 @@ class ApiController extends AbstractController
return $this->json(['status' => 200, 'message' => 'Added to Queue']);
}
}
private function validateUrl(string $url): bool
{
$knownLengths = [
'2119075' => 'file_removed', // 'File is removed by copyright owners' Real Debrid video
'1184727' => 'file_downloading', // 'Torrent is Downloading' Real Debrid video
];
$contentLength = get_headers($url)['Content-Length'];
if (array_key_exists($contentLength, $knownLengths)) {
$exception = new RealDebridBadUrlException($knownLengths[$contentLength]);
$this->logger->error($exception->getMessage());
throw $exception;
}
return true;
}
}

View File

@@ -2,8 +2,10 @@
namespace App\User\Framework\Controller\Web;
use App\User\Action\Handler\RegisterUserHandler;
use App\User\Framework\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;