wip-feat: adds download message queue logic
This commit is contained in:
17
.env
17
.env
@@ -18,3 +18,20 @@
|
|||||||
APP_ENV=dev
|
APP_ENV=dev
|
||||||
APP_SECRET=
|
APP_SECRET=
|
||||||
###< symfony/framework-bundle ###
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||||
|
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||||
|
#
|
||||||
|
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||||
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
|
||||||
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
||||||
|
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
||||||
|
###> symfony/messenger ###
|
||||||
|
# Choose one of the transports below
|
||||||
|
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
|
||||||
|
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
|
||||||
|
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||||
|
###< symfony/messenger ###
|
||||||
|
|||||||
17
.env.dist
17
.env.dist
@@ -1 +1,18 @@
|
|||||||
DATABASE_URL="%%db_url%%"
|
DATABASE_URL="%%db_url%%"
|
||||||
|
|
||||||
|
###> doctrine/doctrine-bundle ###
|
||||||
|
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||||
|
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||||
|
#
|
||||||
|
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||||
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
|
||||||
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
||||||
|
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
|
||||||
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
||||||
|
###> symfony/messenger ###
|
||||||
|
# Choose one of the transports below
|
||||||
|
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
|
||||||
|
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
|
||||||
|
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
||||||
|
###< symfony/messenger ###
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"1tomany/rich-bundle": "^1.8",
|
"1tomany/rich-bundle": "^1.8",
|
||||||
|
"doctrine/dbal": "^3",
|
||||||
|
"doctrine/doctrine-bundle": "^2.14",
|
||||||
|
"doctrine/doctrine-migrations-bundle": "^3.4",
|
||||||
|
"doctrine/orm": "^3.3",
|
||||||
"nihilarr/parse-torrent-name": "^0.0.1",
|
"nihilarr/parse-torrent-name": "^0.0.1",
|
||||||
"nyholm/psr7": "*",
|
"nyholm/psr7": "*",
|
||||||
"p3k/emoji-detector": "^1.2",
|
"p3k/emoji-detector": "^1.2",
|
||||||
@@ -16,7 +20,9 @@
|
|||||||
"symfony/console": "7.2.*",
|
"symfony/console": "7.2.*",
|
||||||
"symfony/dotenv": "7.2.*",
|
"symfony/dotenv": "7.2.*",
|
||||||
"symfony/flex": "^2",
|
"symfony/flex": "^2",
|
||||||
|
"symfony/form": "7.2.*",
|
||||||
"symfony/framework-bundle": "7.2.*",
|
"symfony/framework-bundle": "7.2.*",
|
||||||
|
"symfony/messenger": "7.2.*",
|
||||||
"symfony/runtime": "7.2.*",
|
"symfony/runtime": "7.2.*",
|
||||||
"symfony/security-bundle": "7.2.*",
|
"symfony/security-bundle": "7.2.*",
|
||||||
"symfony/stimulus-bundle": "^2.24",
|
"symfony/stimulus-bundle": "^2.24",
|
||||||
|
|||||||
1778
composer.lock
generated
1778
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -11,4 +11,6 @@ return [
|
|||||||
OneToMany\RichBundle\RichBundle::class => ['all' => true],
|
OneToMany\RichBundle\RichBundle::class => ['all' => true],
|
||||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||||
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
||||||
|
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||||
|
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
11
config/packages/csrf.yaml
Normal file
11
config/packages/csrf.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Enable stateless CSRF protection for forms and logins/logouts
|
||||||
|
framework:
|
||||||
|
form:
|
||||||
|
csrf_protection:
|
||||||
|
token_id: submit
|
||||||
|
|
||||||
|
csrf_protection:
|
||||||
|
stateless_token_ids:
|
||||||
|
- submit
|
||||||
|
- authenticate
|
||||||
|
- logout
|
||||||
60
config/packages/doctrine.yaml
Normal file
60
config/packages/doctrine.yaml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
url: '%env(resolve:DATABASE_URL)%'
|
||||||
|
|
||||||
|
# IMPORTANT: You MUST configure your server version,
|
||||||
|
# either here or in the DATABASE_URL env var (see .env file)
|
||||||
|
#server_version: '16'
|
||||||
|
|
||||||
|
profiling_collect_backtrace: '%kernel.debug%'
|
||||||
|
use_savepoints: true
|
||||||
|
orm:
|
||||||
|
auto_generate_proxy_classes: true
|
||||||
|
enable_lazy_ghost_objects: true
|
||||||
|
report_fields_where_declared: true
|
||||||
|
validate_xml_mapping: true
|
||||||
|
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||||
|
identity_generation_preferences:
|
||||||
|
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
|
||||||
|
auto_mapping: true
|
||||||
|
mappings:
|
||||||
|
# App:
|
||||||
|
# type: attribute
|
||||||
|
# is_bundle: false
|
||||||
|
# dir: '%kernel.project_dir%/src/Entity'
|
||||||
|
# prefix: 'App\Entity'
|
||||||
|
# alias: App
|
||||||
|
Download:
|
||||||
|
type: attribute
|
||||||
|
is_bundle: false
|
||||||
|
dir: '%kernel.project_dir%/src/Download/Framework/Entity'
|
||||||
|
prefix: 'App\Download\Framework\Entity'
|
||||||
|
alias: Download
|
||||||
|
controller_resolver:
|
||||||
|
auto_mapping: false
|
||||||
|
|
||||||
|
when@test:
|
||||||
|
doctrine:
|
||||||
|
dbal:
|
||||||
|
# "TEST_TOKEN" is typically set by ParaTest
|
||||||
|
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
doctrine:
|
||||||
|
orm:
|
||||||
|
auto_generate_proxy_classes: false
|
||||||
|
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
|
||||||
|
query_cache_driver:
|
||||||
|
type: pool
|
||||||
|
pool: doctrine.system_cache_pool
|
||||||
|
result_cache_driver:
|
||||||
|
type: pool
|
||||||
|
pool: doctrine.result_cache_pool
|
||||||
|
|
||||||
|
framework:
|
||||||
|
cache:
|
||||||
|
pools:
|
||||||
|
doctrine.result_cache_pool:
|
||||||
|
adapter: cache.app
|
||||||
|
doctrine.system_cache_pool:
|
||||||
|
adapter: cache.system
|
||||||
6
config/packages/doctrine_migrations.yaml
Normal file
6
config/packages/doctrine_migrations.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
doctrine_migrations:
|
||||||
|
migrations_paths:
|
||||||
|
# namespace is arbitrary but should be different from App\Migrations
|
||||||
|
# as migrations classes should NOT be autoloaded
|
||||||
|
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
||||||
|
enable_profiler: false
|
||||||
22
config/packages/messenger.yaml
Normal file
22
config/packages/messenger.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
framework:
|
||||||
|
messenger:
|
||||||
|
# Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
|
||||||
|
# failure_transport: failed
|
||||||
|
|
||||||
|
transports:
|
||||||
|
# https://symfony.com/doc/current/messenger.html#transport-configuration
|
||||||
|
# async: '%env(MESSENGER_TRANSPORT_DSN)%'
|
||||||
|
# failed: 'doctrine://default?queue_name=failed'
|
||||||
|
# sync: 'sync://'
|
||||||
|
|
||||||
|
routing:
|
||||||
|
# Route your messages to the transports
|
||||||
|
# 'App\Message\YourMessage': async
|
||||||
|
|
||||||
|
# when@test:
|
||||||
|
# framework:
|
||||||
|
# messenger:
|
||||||
|
# transports:
|
||||||
|
# # replace with your transport name here (e.g., my_transport: 'in-memory://')
|
||||||
|
# # For more Messenger testing tools, see https://github.com/zenstruck/messenger-test
|
||||||
|
# async: 'in-memory://'
|
||||||
@@ -22,3 +22,4 @@ services:
|
|||||||
|
|
||||||
# add more service definitions when explicit configuration is needed
|
# add more service definitions when explicit configuration is needed
|
||||||
# please note that last definitions always *replace* previous ones
|
# please note that last definitions always *replace* previous ones
|
||||||
|
App\Download\Downloader\DownloaderInterface: "@App\\Download\\Downloader\\ProcessDownloader"
|
||||||
|
|||||||
0
migrations/.gitignore
vendored
Executable file
0
migrations/.gitignore
vendored
Executable file
31
migrations/Version20241211055503.php
Normal file
31
migrations/Version20241211055503.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241211055503 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', available_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', delivered_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('DROP TABLE messenger_messages');
|
||||||
|
}
|
||||||
|
}
|
||||||
43
migrations/Version20241218024301.php
Normal file
43
migrations/Version20241218024301.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241218024301 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE episode (id INT AUTO_INCREMENT NOT NULL, series_id_id INT DEFAULT NULL, imdb_id VARCHAR(255) DEFAULT NULL, tvdb_id VARCHAR(255) DEFAULT NULL, title VARCHAR(255) DEFAULT NULL, year VARCHAR(5) DEFAULT NULL, poster VARCHAR(500) DEFAULT NULL, season VARCHAR(255) DEFAULT NULL, episode VARCHAR(255) DEFAULT NULL, episode_code VARCHAR(255) DEFAULT NULL, download_directory VARCHAR(500) DEFAULT NULL, INDEX IDX_DDAA1CDAACB7A4A (series_id_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('CREATE TABLE series (id INT AUTO_INCREMENT NOT NULL, imdb_id VARCHAR(255) NOT NULL, tvdb_id VARCHAR(255) DEFAULT NULL, title VARCHAR(255) DEFAULT NULL, year VARCHAR(5) DEFAULT NULL, poster VARCHAR(500) DEFAULT NULL, directory VARCHAR(255) DEFAULT NULL, number_seasons INT DEFAULT NULL, number_episodes INT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('ALTER TABLE episode ADD CONSTRAINT FK_DDAA1CDAACB7A4A FOREIGN KEY (series_id_id) REFERENCES series (id)');
|
||||||
|
$this->addSql('DROP INDEX IDX_75EA56E016BA31DB ON messenger_messages');
|
||||||
|
$this->addSql('DROP INDEX IDX_75EA56E0FB7336F0 ON messenger_messages');
|
||||||
|
$this->addSql('DROP INDEX IDX_75EA56E0E3BD61CE ON messenger_messages');
|
||||||
|
$this->addSql('ALTER TABLE messenger_messages CHANGE id id INT AUTO_INCREMENT NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE episode DROP FOREIGN KEY FK_DDAA1CDAACB7A4A');
|
||||||
|
$this->addSql('DROP TABLE episode');
|
||||||
|
$this->addSql('DROP TABLE series');
|
||||||
|
$this->addSql('ALTER TABLE messenger_messages CHANGE id id BIGINT AUTO_INCREMENT NOT NULL');
|
||||||
|
$this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
migrations/Version20241226201901.php
Normal file
31
migrations/Version20241226201901.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241226201901 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
31
migrations/Version20241226205937.php
Normal file
31
migrations/Version20241226205937.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241226205937 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE download (id INT AUTO_INCREMENT NOT NULL, imdb_id VARCHAR(20) DEFAULT NULL, title VARCHAR(255) DEFAULT NULL, url VARCHAR(1024) NOT NULL, filename VARCHAR(1024) DEFAULT NULL, status VARCHAR(255) DEFAULT NULL, progress INT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('DROP TABLE download');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
migrations/Version20241226214700.php
Normal file
31
migrations/Version20241226214700.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20241226214700 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE download ADD media_type VARCHAR(255) DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE download DROP media_type');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
migrations/Version20250202035615.php
Normal file
31
migrations/Version20250202035615.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20250202035615 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE download ADD batch_id VARCHAR(255) DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE download DROP batch_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
32
migrations/Version20250217221120.php
Normal file
32
migrations/Version20250217221120.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20250217221120 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE processed_messages (id INT AUTO_INCREMENT NOT NULL, run_id INT NOT NULL, attempt SMALLINT NOT NULL, message_type VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, dispatched_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', received_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', finished_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', wait_time BIGINT NOT NULL, handle_time BIGINT NOT NULL, memory_usage INT NOT NULL, transport VARCHAR(255) NOT NULL, tags VARCHAR(255) DEFAULT NULL, failure_type VARCHAR(255) DEFAULT NULL, failure_message LONGTEXT DEFAULT NULL, results JSON DEFAULT NULL COMMENT \'(DC2Type:json)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE preferences (id INT AUTO_INCREMENT NOT NULL, value VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
|
||||||
|
$this->addSql('DROP TABLE processed_messages');
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/Controller/DownloadController.php
Normal file
25
src/Controller/DownloadController.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Download\Action\Input\DownloadMediaInput;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
class DownloadController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private MessageBusInterface $bus,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
#[Route('/download', name: 'app_download', methods: ['POST'])]
|
||||||
|
public function download(
|
||||||
|
DownloadMediaInput $input,
|
||||||
|
): Response {
|
||||||
|
$this->bus->dispatch($input->toCommand());
|
||||||
|
|
||||||
|
return $this->json(['status' => 200, 'message' => 'Added to Queue']);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/Download/Action/Command/DownloadMediaCommand.php
Normal file
19
src/Download/Action/Command/DownloadMediaCommand.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Action\Command;
|
||||||
|
|
||||||
|
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements CommandInterface<DownloadMediaCommand>
|
||||||
|
*/
|
||||||
|
class DownloadMediaCommand implements CommandInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $url,
|
||||||
|
public string $title,
|
||||||
|
public string $filename,
|
||||||
|
public string $mediaType,
|
||||||
|
public string $imdbId,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Download\Action\Command;
|
|
||||||
|
|
||||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
|
||||||
|
|
||||||
class GetDownloadOptionsCommand implements CommandInterface
|
|
||||||
{
|
|
||||||
/** @implements CommandInterface<GetDownloadOptionsCommand> */
|
|
||||||
public function __construct(
|
|
||||||
public string $tmdbId,
|
|
||||||
public string $mediaType,
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
58
src/Download/Action/Handler/DownloadMediaHandler.php
Normal file
58
src/Download/Action/Handler/DownloadMediaHandler.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Action\Handler;
|
||||||
|
|
||||||
|
use App\Download\Action\Command\DownloadMediaCommand;
|
||||||
|
use App\Download\Action\Result\DownloadMediaResult;
|
||||||
|
use App\Download\Framework\Repository\DownloadRepository;
|
||||||
|
use App\Download\Downloader\DownloaderInterface;
|
||||||
|
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||||
|
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||||
|
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||||
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
|
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
|
||||||
|
|
||||||
|
/** @implements HandlerInterface<DownloadMediaCommand, DownloadMediaResult> */
|
||||||
|
#[AsMessageHandler]
|
||||||
|
readonly class DownloadMediaHandler implements HandlerInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private DownloaderInterface $downloader,
|
||||||
|
private DownloadRepository $downloadRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function __invoke(CommandInterface $command)
|
||||||
|
{
|
||||||
|
$this->handle($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(CommandInterface $command): ResultInterface
|
||||||
|
{
|
||||||
|
$download = $this->downloadRepository->insert(
|
||||||
|
$command->url,
|
||||||
|
$command->title,
|
||||||
|
$command->filename,
|
||||||
|
$command->imdbId,
|
||||||
|
$command->mediaType,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->downloadRepository->updateStatus($download->getId(), 'In Progress');
|
||||||
|
|
||||||
|
$this->downloader->download(
|
||||||
|
$command->mediaType,
|
||||||
|
$command->title,
|
||||||
|
$command->url,
|
||||||
|
$download->getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->downloadRepository->updateStatus($download->getId(), 'Complete');
|
||||||
|
|
||||||
|
} catch (\Throwable $exception) {
|
||||||
|
throw new UnrecoverableMessageHandlingException($exception->getMessage(), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DownloadMediaResult(200, "Success.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Download\Action\Handler;
|
|
||||||
|
|
||||||
use App\Tmdb\Tmdb;
|
|
||||||
use App\Torrentio\Client\Torrentio;
|
|
||||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
|
||||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
|
||||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
|
||||||
|
|
||||||
class GetDownloadOptionsHandler implements HandlerInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly Tmdb $tmdb,
|
|
||||||
private readonly Torrentio $torrentio,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function handle(CommandInterface $command): ResultInterface
|
|
||||||
{
|
|
||||||
$media = $this->tmdb->mediaDetails($command->tmdbId, $command->mediaType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
40
src/Download/Action/Input/DownloadMediaInput.php
Normal file
40
src/Download/Action/Input/DownloadMediaInput.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Action\Input;
|
||||||
|
|
||||||
|
use App\Download\Action\Command\DownloadMediaCommand;
|
||||||
|
use OneToMany\RichBundle\Attribute\SourceRequest;
|
||||||
|
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||||
|
use OneToMany\RichBundle\Contract\InputInterface;
|
||||||
|
|
||||||
|
/** @implements InputInterface<DownloadMediaInput> */
|
||||||
|
class DownloadMediaInput implements InputInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
#[SourceRequest('url')]
|
||||||
|
public string $url,
|
||||||
|
|
||||||
|
#[SourceRequest('title')]
|
||||||
|
public string $title,
|
||||||
|
|
||||||
|
#[SourceRequest('filename')]
|
||||||
|
public string $filename,
|
||||||
|
|
||||||
|
#[SourceRequest('mediaType')]
|
||||||
|
public string $mediaType,
|
||||||
|
|
||||||
|
#[SourceRequest('imdbId')]
|
||||||
|
public string $imdbId,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function toCommand(): CommandInterface
|
||||||
|
{
|
||||||
|
return new DownloadMediaCommand(
|
||||||
|
$this->url,
|
||||||
|
$this->title,
|
||||||
|
$this->filename,
|
||||||
|
$this->mediaType,
|
||||||
|
$this->imdbId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Download\Action\Input;
|
|
||||||
|
|
||||||
use App\Download\Action\Command\GetDownloadOptionsCommand;
|
|
||||||
use OneToMany\RichBundle\Attribute\SourceRoute;
|
|
||||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
|
||||||
use OneToMany\RichBundle\Contract\InputInterface;
|
|
||||||
|
|
||||||
class GetDownloadOptionsInput implements InputInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
#[SourceRoute('tmdbId')]
|
|
||||||
public string $tmdbId,
|
|
||||||
|
|
||||||
#[SourceRoute('mediaType')]
|
|
||||||
public string $mediaType,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function toCommand(): CommandInterface
|
|
||||||
{
|
|
||||||
return new GetDownloadOptionsCommand($this->tmdbId, $this->mediaType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
src/Download/Action/Result/DownloadMediaResult.php
Normal file
14
src/Download/Action/Result/DownloadMediaResult.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Action\Result;
|
||||||
|
|
||||||
|
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||||
|
|
||||||
|
/** @implements ResultInterface<DownloadMediaResult> */
|
||||||
|
class DownloadMediaResult implements ResultInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public int $status,
|
||||||
|
public string $message,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Download\Action\Result;
|
|
||||||
|
|
||||||
use App\Tmdb\TmdbResult;
|
|
||||||
|
|
||||||
class GetDownloadOptionsResult
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public TmdbResult $media,
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
20
src/Download/Downloader/DownloaderInterface.php
Normal file
20
src/Download/Downloader/DownloaderInterface.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Downloader;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Message\DownloadMessage;
|
||||||
|
use App\Message\DownloadMovieMessage;
|
||||||
|
use App\Message\DownloadTvShowMessage;
|
||||||
|
|
||||||
|
interface DownloaderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $baseDir
|
||||||
|
* @param string $title
|
||||||
|
* @param string $url
|
||||||
|
* @return void
|
||||||
|
* Downloads the requested file.
|
||||||
|
*/
|
||||||
|
public function download(string $baseDir, string $title, string $url, ?int $downloadId): void;
|
||||||
|
}
|
||||||
64
src/Download/Downloader/ProcessDownloader.php
Normal file
64
src/Download/Downloader/ProcessDownloader.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Downloader;
|
||||||
|
|
||||||
|
use App\Download\Framework\Entity\Download;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||||
|
use Symfony\Component\Process\Process;
|
||||||
|
|
||||||
|
class ProcessDownloader implements DownloaderInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private EntityManagerInterface $entityManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function download(string $baseDir, string $title, string $url, ?int $downloadId): void
|
||||||
|
{
|
||||||
|
/** @var Download $downloadEntity */
|
||||||
|
$downloadEntity = $this->entityManager->getRepository(Download::class)->find($downloadId);
|
||||||
|
$downloadEntity->setProgress(0);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$process = new Process([
|
||||||
|
'/bin/sh',
|
||||||
|
'/var/www/bash/app/wget_download.sh',
|
||||||
|
$baseDir,
|
||||||
|
$title,
|
||||||
|
$url
|
||||||
|
]);
|
||||||
|
|
||||||
|
$process->setTimeout(1800); // 30 min
|
||||||
|
$process->setIdleTimeout(600); // 10 min
|
||||||
|
|
||||||
|
$process->start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$progress = 0;
|
||||||
|
$this->entityManager->flush();
|
||||||
|
$process->wait(function ($type, $buffer) use ($progress, $downloadEntity): void {
|
||||||
|
if (Process::ERR === $type) {
|
||||||
|
$pregMatchOutput = [];
|
||||||
|
preg_match('/[\d]+%/', $buffer, $pregMatchOutput);
|
||||||
|
|
||||||
|
if (!empty($pregMatchOutput)) {
|
||||||
|
if ($pregMatchOutput[0] !== $progress) {
|
||||||
|
$progress = (int) $pregMatchOutput[0];
|
||||||
|
$downloadEntity->setProgress($progress);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fwrite(STDOUT, $buffer);
|
||||||
|
});
|
||||||
|
$downloadEntity->setProgress(100);
|
||||||
|
} catch (ProcessFailedException $exception) {
|
||||||
|
$downloadEntity->setStatus('Failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/Download/Downloader/WgetDownloader.php
Normal file
27
src/Download/Downloader/WgetDownloader.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Downloader;
|
||||||
|
|
||||||
|
use App\Message\DownloadMessage;
|
||||||
|
use App\Message\DownloadMovieMessage;
|
||||||
|
use App\Message\DownloadTvShowMessage;
|
||||||
|
|
||||||
|
class WgetDownloader implements DownloaderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* SSHs into the NAS and performs the download.
|
||||||
|
* This way retains the fast DL speed on the NAS.
|
||||||
|
*/
|
||||||
|
public function download(string $baseDir, string $title, string $url, ?int $downloadId): void
|
||||||
|
{
|
||||||
|
// SSHs into the NAS, cds into movies dir, makes new dir based on filename, cds into that dir, downloads movie
|
||||||
|
system(sprintf(
|
||||||
|
'sh /var/www/bash/app/wget_download.sh "%s" "%s" "%s"',
|
||||||
|
$baseDir,
|
||||||
|
$title,
|
||||||
|
$url
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/Download/Framework/Entity/.gitignore
vendored
Normal file
0
src/Download/Framework/Entity/.gitignore
vendored
Normal file
149
src/Download/Framework/Entity/Download.php
Normal file
149
src/Download/Framework/Entity/Download.php
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Framework\Entity;
|
||||||
|
|
||||||
|
use App\Repository\DownloadRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\UX\Turbo\Attribute\Broadcast;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: DownloadRepository::class)]
|
||||||
|
#[Broadcast]
|
||||||
|
class Download
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 20, nullable: true)]
|
||||||
|
private ?string $imdbId = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $mediaType = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $title = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 1024)]
|
||||||
|
private ?string $url = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 1024, nullable: true)]
|
||||||
|
private ?string $filename = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $status = null;
|
||||||
|
|
||||||
|
#[ORM\Column(nullable: true)]
|
||||||
|
private ?int $progress = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $batchId = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setId(int $id): static
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImdbId(): ?string
|
||||||
|
{
|
||||||
|
return $this->imdbId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setImdbId(?string $imdbId): static
|
||||||
|
{
|
||||||
|
$this->imdbId = $imdbId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMediaType(): ?string
|
||||||
|
{
|
||||||
|
return $this->mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMediaType(?string $mediaType): static
|
||||||
|
{
|
||||||
|
$this->mediaType = $mediaType;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): ?string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle(?string $title): static
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrl(): ?string
|
||||||
|
{
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUrl(string $url): static
|
||||||
|
{
|
||||||
|
$this->url = $url;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilename(): ?string
|
||||||
|
{
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFilename(?string $filename): static
|
||||||
|
{
|
||||||
|
$this->filename = $filename;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatus(): ?string
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStatus(?string $status): static
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProgress(): ?int
|
||||||
|
{
|
||||||
|
return $this->progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProgress(?int $progress): static
|
||||||
|
{
|
||||||
|
$this->progress = $progress;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBatchId(): ?string
|
||||||
|
{
|
||||||
|
return $this->batchId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBatchId(?string $batchId): static
|
||||||
|
{
|
||||||
|
$this->batchId = $batchId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/Download/Framework/Repository/.gitignore
vendored
Normal file
0
src/Download/Framework/Repository/.gitignore
vendored
Normal file
118
src/Download/Framework/Repository/DownloadRepository.php
Normal file
118
src/Download/Framework/Repository/DownloadRepository.php
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Download\Framework\Repository;
|
||||||
|
|
||||||
|
use App\Download\Framework\Entity\Download;
|
||||||
|
use App\ValueObject\DownloadRequest;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use Knp\Component\Pager\Paginator;
|
||||||
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<Download>
|
||||||
|
*/
|
||||||
|
class DownloadRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
private ManagerRegistry $managerRegistry;
|
||||||
|
|
||||||
|
public function __construct(ManagerRegistry $registry, ManagerRegistry $managerRegistry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, Download::class);
|
||||||
|
$this->managerRegistry = $managerRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompletePaginated(int $pageNumber = 1, int $perPage = 10)
|
||||||
|
{
|
||||||
|
$firstResult = ($pageNumber - 1) * $perPage;
|
||||||
|
$query = $this->createQueryBuilder('d')
|
||||||
|
->andWhere('d.status IN (:statuses)')
|
||||||
|
->orderBy('d.id', 'DESC')
|
||||||
|
->setParameter('statuses', ['Complete'])
|
||||||
|
->setFirstResult($firstResult)
|
||||||
|
->setMaxResults($perPage)
|
||||||
|
->getQuery();
|
||||||
|
|
||||||
|
return new \Doctrine\ORM\Tools\Pagination\Paginator($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActivePaginated(int $pageNumber = 1, int $perPage = 10)
|
||||||
|
{
|
||||||
|
$firstResult = ($pageNumber - 1) * $perPage;
|
||||||
|
$query = $this->createQueryBuilder('d')
|
||||||
|
->andWhere('d.status IN (:statuses)')
|
||||||
|
->setParameter('statuses', ['New', 'In Progress'])
|
||||||
|
->setFirstResult($firstResult)
|
||||||
|
->setMaxResults($perPage)
|
||||||
|
->getQuery();
|
||||||
|
|
||||||
|
return new \Doctrine\ORM\Tools\Pagination\Paginator($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insert(
|
||||||
|
string $url,
|
||||||
|
string $title,
|
||||||
|
string $filename,
|
||||||
|
string $imdbId,
|
||||||
|
string $mediaType,
|
||||||
|
string $batchId,
|
||||||
|
string $status = 'New'
|
||||||
|
): Download {
|
||||||
|
$download = (new Download())
|
||||||
|
->setUrl($url)
|
||||||
|
->setTitle($title)
|
||||||
|
->setFilename($filename)
|
||||||
|
->setImdbId($imdbId)
|
||||||
|
->setMediaType($mediaType)
|
||||||
|
->setBatchId($batchId)
|
||||||
|
->setStatus($status);
|
||||||
|
|
||||||
|
$this->getEntityManager()->persist($download);
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
|
||||||
|
return $download;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertFromDownloadRequest(DownloadRequest $request): Download
|
||||||
|
{
|
||||||
|
$download = (new Download())
|
||||||
|
->setUrl($request->downloadUrl)
|
||||||
|
->setTitle($request->seriesName)
|
||||||
|
->setFilename($request->filename)
|
||||||
|
->setImdbId($request->imdbCode)
|
||||||
|
->setMediaType($request->mediaType)
|
||||||
|
->setStatus('New');
|
||||||
|
|
||||||
|
$this->getEntityManager()->persist($download);
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
|
||||||
|
return $download;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateStatus(int $id, string $status): Download
|
||||||
|
{
|
||||||
|
$download = $this->find($id);
|
||||||
|
$download->setStatus($status);
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
return $download;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(int $id)
|
||||||
|
{
|
||||||
|
$entity = $this->find($id);
|
||||||
|
$this->getEntityManager()->remove($entity);
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPendingByBatchId(string $batchId): ?array
|
||||||
|
{
|
||||||
|
$query = $this->createQueryBuilder('d')
|
||||||
|
->andWhere('d.status IN (:statuses)')
|
||||||
|
->andWhere('d.batchId = :batchId')
|
||||||
|
->setParameter('statuses', ['New', 'In Progress'])
|
||||||
|
->setParameter('batchId', $batchId)
|
||||||
|
->getQuery();
|
||||||
|
|
||||||
|
return $query->getResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Search\Action\Input;
|
namespace App\Search\Action\Input;
|
||||||
|
|
||||||
use App\Download\Action\Command\GetDownloadOptionsCommand;
|
use App\Download\Action\Command\DownloadMediaCommand;
|
||||||
use App\Search\Action\Command\GetMediaInfoCommand;
|
use App\Search\Action\Command\GetMediaInfoCommand;
|
||||||
use OneToMany\RichBundle\Attribute\SourceRoute;
|
use OneToMany\RichBundle\Attribute\SourceRoute;
|
||||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||||
|
|||||||
51
symfony.lock
51
symfony.lock
@@ -2,6 +2,33 @@
|
|||||||
"1tomany/rich-bundle": {
|
"1tomany/rich-bundle": {
|
||||||
"version": "v1.8.3"
|
"version": "v1.8.3"
|
||||||
},
|
},
|
||||||
|
"doctrine/doctrine-bundle": {
|
||||||
|
"version": "2.14",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "2.13",
|
||||||
|
"ref": "8d96c0b51591ffc26794d865ba3ee7d193438a83"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/doctrine.yaml",
|
||||||
|
"src/Entity/.gitignore",
|
||||||
|
"src/Repository/.gitignore"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"doctrine/doctrine-migrations-bundle": {
|
||||||
|
"version": "3.4",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "3.1",
|
||||||
|
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/doctrine_migrations.yaml",
|
||||||
|
"migrations/.gitignore"
|
||||||
|
]
|
||||||
|
},
|
||||||
"php-http/discovery": {
|
"php-http/discovery": {
|
||||||
"version": "1.20",
|
"version": "1.20",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@@ -54,6 +81,18 @@
|
|||||||
".env.dev"
|
".env.dev"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/form": {
|
||||||
|
"version": "7.2",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "7.2",
|
||||||
|
"ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/csrf.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/framework-bundle": {
|
"symfony/framework-bundle": {
|
||||||
"version": "7.2",
|
"version": "7.2",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@@ -82,6 +121,18 @@
|
|||||||
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"symfony/messenger": {
|
||||||
|
"version": "7.2",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "6.0",
|
||||||
|
"ref": "ba1ac4e919baba5644d31b57a3284d6ba12d52ee"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/messenger.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/routing": {
|
"symfony/routing": {
|
||||||
"version": "7.2",
|
"version": "7.2",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
Reference in New Issue
Block a user