Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 891ce81902 | |||
| b7d7025114 | |||
| 41114446d0 | |||
| 592e02484e | |||
| bd9fde94d1 |
@@ -1,5 +1,23 @@
|
|||||||
{
|
{
|
||||||
"controllers": {
|
"controllers": {
|
||||||
|
"@spomky-labs/pwa-bundle": {
|
||||||
|
"connection-status": {
|
||||||
|
"enabled": true,
|
||||||
|
"fetch": "eager"
|
||||||
|
},
|
||||||
|
"backgroundsync-form": {
|
||||||
|
"enabled": true,
|
||||||
|
"fetch": "eager"
|
||||||
|
},
|
||||||
|
"sync-broadcast": {
|
||||||
|
"enabled": true,
|
||||||
|
"fetch": "eager"
|
||||||
|
},
|
||||||
|
"prefetch-on-demand": {
|
||||||
|
"enabled": true,
|
||||||
|
"fetch": "eager"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@symfony/ux-autocomplete": {
|
"@symfony/ux-autocomplete": {
|
||||||
"autocomplete": {
|
"autocomplete": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"php-tmdb/api": "^4.1",
|
"php-tmdb/api": "^4.1",
|
||||||
"predis/predis": "^2.4",
|
"predis/predis": "^2.4",
|
||||||
"runtime/frankenphp-symfony": "^0.2.0",
|
"runtime/frankenphp-symfony": "^0.2.0",
|
||||||
|
"spomky-labs/pwa-bundle": "^1.2",
|
||||||
"stof/doctrine-extensions-bundle": "^1.14",
|
"stof/doctrine-extensions-bundle": "^1.14",
|
||||||
"symfony/asset": "7.3.*",
|
"symfony/asset": "7.3.*",
|
||||||
"symfony/console": "7.3.*",
|
"symfony/console": "7.3.*",
|
||||||
|
|||||||
123
composer.lock
generated
123
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "bfbdc7ee820da20b824f4b1933fe967b",
|
"content-hash": "0f98dada0a01d471cebf4eb1b51b9006",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "1tomany/rich-bundle",
|
"name": "1tomany/rich-bundle",
|
||||||
@@ -4866,6 +4866,127 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-06-13T08:35:04+00:00"
|
"time": "2025-06-13T08:35:04+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spomky-labs/pwa-bundle",
|
||||||
|
"version": "1.2.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Spomky-Labs/pwa-bundle.git",
|
||||||
|
"reference": "c24711ea8428d14a01132d9e42cb17d84218a1ee"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Spomky-Labs/pwa-bundle/zipball/c24711ea8428d14a01132d9e42cb17d84218a1ee",
|
||||||
|
"reference": "c24711ea8428d14a01132d9e42cb17d84218a1ee",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"phpdocumentor/reflection-docblock": "^5.3",
|
||||||
|
"psr/log": "^1.0|^2.0|^3.0",
|
||||||
|
"symfony/asset": "^6.4|^7.0",
|
||||||
|
"symfony/asset-mapper": "^6.4|^7.0",
|
||||||
|
"symfony/config": "^6.4|^7.0",
|
||||||
|
"symfony/dependency-injection": "^6.4|^7.0",
|
||||||
|
"symfony/deprecation-contracts": "^3.5",
|
||||||
|
"symfony/http-kernel": "^6.4|^7.0",
|
||||||
|
"symfony/property-access": "^6.4|^7.0",
|
||||||
|
"symfony/property-info": "^6.4|^7.0",
|
||||||
|
"symfony/routing": "^6.4|^7.0",
|
||||||
|
"symfony/serializer": "^6.4|^7.0",
|
||||||
|
"twig/twig": "^3.8"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dbrekelmans/bdi": "^1.1",
|
||||||
|
"ekino/phpstan-banned-code": "^1.0|^2.0|^3.0",
|
||||||
|
"ergebnis/phpunit-slow-test-detector": "^2.14",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"infection/infection": "^0.28|^0.29",
|
||||||
|
"matthiasnoback/symfony-config-test": "^5.1",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||||
|
"phpstan/extension-installer": "^1.1",
|
||||||
|
"phpstan/phpdoc-parser": "^1.28|^2.0",
|
||||||
|
"phpstan/phpstan": "^1.0|^2.0",
|
||||||
|
"phpstan/phpstan-beberlei-assert": "^1.0|^2.0",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.4|^2.0",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1.0|^2.0",
|
||||||
|
"phpstan/phpstan-symfony": "^1.4|^2.0",
|
||||||
|
"phpunit/phpunit": "^10.1|^11.0",
|
||||||
|
"rector/rector": "^1.0|^2.0",
|
||||||
|
"staabm/phpstan-todo-by": "^0.1.27|^0.2",
|
||||||
|
"struggle-for-php/sfp-phpstan-psr-log": "^0.21.0|^0.22|^0.23",
|
||||||
|
"symfony/filesystem": "^6.4|^7.0",
|
||||||
|
"symfony/framework-bundle": "^6.4|^7.0",
|
||||||
|
"symfony/mime": "^6.4|^7.0",
|
||||||
|
"symfony/monolog-bundle": "^3.10",
|
||||||
|
"symfony/panther": "^2.1",
|
||||||
|
"symfony/phpunit-bridge": "^6.4|^7.0",
|
||||||
|
"symfony/translation": "^7.0",
|
||||||
|
"symfony/yaml": "^6.4|^7.0",
|
||||||
|
"symplify/easy-coding-standard": "^12.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Required to generate icons (or Imagick).",
|
||||||
|
"ext-imagick": "Required to generate icons (or GD).",
|
||||||
|
"symfony/filesystem": "For generating and manipulating icons or screenshots",
|
||||||
|
"symfony/mime": "For generating and manipulating icons or screenshots",
|
||||||
|
"symfony/panther": "For generating screenshots directly from your application"
|
||||||
|
},
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/spomky-labs/pwa-bundle",
|
||||||
|
"name": "spomky-labs/pwa-bundle"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"SpomkyLabs\\PwaBundle\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Florent Morselli",
|
||||||
|
"homepage": "https://github.com/Spomky"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "All contributors",
|
||||||
|
"homepage": "https://github.com/spomky-labs/pwa-bundle/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Progressive Web App Manifest Generator Bundle for Symfony.",
|
||||||
|
"homepage": "https://github.com/spomky-labs",
|
||||||
|
"keywords": [
|
||||||
|
"bundle",
|
||||||
|
"pwa",
|
||||||
|
"symfony",
|
||||||
|
"symfony-ux"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Spomky-Labs/pwa-bundle/issues",
|
||||||
|
"source": "https://github.com/Spomky-Labs/pwa-bundle/tree/1.2.5"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.buymeacoffee.com/FlorentMorselli",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/Spomky",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/FlorentMorselli",
|
||||||
|
"type": "patreon"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-12-16T08:02:21+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "stof/doctrine-extensions-bundle",
|
"name": "stof/doctrine-extensions-bundle",
|
||||||
"version": "v1.14.0",
|
"version": "v1.14.0",
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ return [
|
|||||||
Symfony\UX\Autocomplete\AutocompleteBundle::class => ['all' => true],
|
Symfony\UX\Autocomplete\AutocompleteBundle::class => ['all' => true],
|
||||||
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
|
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
|
||||||
Drenso\OidcBundle\DrensoOidcBundle::class => ['all' => true],
|
Drenso\OidcBundle\DrensoOidcBundle::class => ['all' => true],
|
||||||
|
SpomkyLabs\PwaBundle\SpomkyLabsPwaBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
21
config/packages/pwa.yaml
Normal file
21
config/packages/pwa.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
pwa:
|
||||||
|
manifest:
|
||||||
|
enabled: true
|
||||||
|
name: "Torsearch"
|
||||||
|
short_name: "torsearch"
|
||||||
|
start_url: "/"
|
||||||
|
display: "standalone"
|
||||||
|
id: "/"
|
||||||
|
background_color: "#083344"
|
||||||
|
theme_color: "#f98e44"
|
||||||
|
description: Torsearch provides a simple and intuitive way to manage your personal media library.
|
||||||
|
icons:
|
||||||
|
- src: "icon.png"
|
||||||
|
sizes: [ 192 ]
|
||||||
|
- src: "icon.png"
|
||||||
|
sizes: [ 192 ]
|
||||||
|
purpose: maskable
|
||||||
|
categories:
|
||||||
|
- entertainment
|
||||||
|
- multimedia
|
||||||
|
- utilities
|
||||||
@@ -7,6 +7,11 @@ APP_URL="https://dev.caldwell.digital"
|
|||||||
APP_SECRET="70169beadfbc8101c393cbfbba27a313"
|
APP_SECRET="70169beadfbc8101c393cbfbba27a313"
|
||||||
APP_ENV=prod
|
APP_ENV=prod
|
||||||
|
|
||||||
|
# Mercure is a Caddy module built into the webserver
|
||||||
|
# that facilitates the usage of websockets to transmit
|
||||||
|
# real time data (download progress, etc.)
|
||||||
|
MERCURE_JWT_SECRET="!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
|
||||||
@@ -19,39 +24,48 @@ DATABASE_URL="mysql://root:password@database:3306/app?serverVersion=10.6.19.2-Ma
|
|||||||
# This key is never saved anywhere
|
# This key is never saved anywhere
|
||||||
# else and is passed to Torrentio
|
# else and is passed to Torrentio
|
||||||
# to retrieve download options
|
# to retrieve download options
|
||||||
#REAL_DEBRID_KEY=""
|
REAL_DEBRID_KEY=""
|
||||||
|
|
||||||
# Enter you TMDB API key
|
# Enter your TMDB API key
|
||||||
# This is used to provide rich search results
|
# This is used to provide rich search results
|
||||||
# when searching for media and rendering the
|
# when searching for media and rendering the
|
||||||
# Popular Movies and TV Shows section.
|
# Popular Movies and TV Shows section.
|
||||||
#TMDB_API=
|
TMDB_API=""
|
||||||
|
|
||||||
REAL_DEBRID_KEY=""
|
|
||||||
TMDB_API=eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI0ZTJjYjJhOGUzOGJhNjdiNjVhOGU1NGM0ZWI1MzhmOCIsIm5iZiI6MTczNzkyNjA0NC41NjQsInN1YiI6IjY3OTZhNTljYzdiMDFiNzJjNzIzZWM5YiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.e8DbNe9qrSBC1y-ANRv-VWBAtls-ZS2r7aNCiI68mpw
|
|
||||||
|
|
||||||
|
|
||||||
MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
|
|
||||||
|
|
||||||
# Use your own Redis instance or use the
|
# Use your own Redis instance or use the
|
||||||
# below value to use the container included
|
# below value to use the container included
|
||||||
# in the example compose.yml file.
|
# in the example compose.yml file.
|
||||||
REDIS_HOST="redis://redis"
|
REDIS_HOST="redis://redis"
|
||||||
|
|
||||||
|
### Auth ###
|
||||||
|
# Change to "oidc" to and provide the required
|
||||||
|
# environment variables below to use OIDC auth.
|
||||||
|
AUTH_METHOD=form_login
|
||||||
|
|
||||||
|
# OIDC
|
||||||
|
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=
|
||||||
|
|
||||||
|
|
||||||
# LDAP Config: To use LDAP, enter the below fields
|
# LDAP Config: To use LDAP, enter the below fields
|
||||||
# and run 'php bin/console config:set auth.method ldap'
|
# and run 'php bin/console config:set auth.method ldap'
|
||||||
LDAP_HOST=
|
# (LDAP is still in progress and not ready for use)
|
||||||
LDAP_PORT=
|
#LDAP_HOST=
|
||||||
LDAP_ENCRYPTION=
|
#LDAP_PORT=
|
||||||
LDAP_BASE_DN=
|
#LDAP_ENCRYPTION=
|
||||||
LDAP_BIND_USER=
|
#LDAP_BASE_DN=
|
||||||
LDAP_BIND_PASS=
|
#LDAP_BIND_USER=
|
||||||
LDAP_DN_STRING=
|
#LDAP_BIND_PASS=
|
||||||
LDAP_UID_KEY="uid"
|
#LDAP_DN_STRING=
|
||||||
|
#LDAP_UID_KEY="uid"
|
||||||
# LDAP group that identifies an Admin
|
# LDAP group that identifies an Admin
|
||||||
# Users with this LDAP group will automatically
|
# Users with this LDAP group will automatically
|
||||||
# get the admin role in this system.
|
# get the admin role in this system.
|
||||||
LDAP_ADMIN_ROLE_DN=""
|
#LDAP_ADMIN_ROLE_DN=""
|
||||||
LDAP_EMAIL_ATTRIBUTE=mail
|
#LDAP_EMAIL_ATTRIBUTE=mail
|
||||||
LDAP_USERNAME_ATTRIBUTE=uid
|
#LDAP_USERNAME_ATTRIBUTE=uid
|
||||||
LDAP_NAME_ATTRIBUTE=displayname
|
#LDAP_NAME_ATTRIBUTE=displayname
|
||||||
|
|||||||
BIN
public/icon.png
Normal file
BIN
public/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Base\Framework\Controller;
|
namespace App\Base\Framework\Controller;
|
||||||
|
|
||||||
use App\Base\Util\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Base\Util;
|
namespace App\Base\Service;
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Download\Framework\Controller;
|
namespace App\Download\Framework\Controller;
|
||||||
|
|
||||||
use App\Base\Util\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
use App\Download\Action\Handler\DeleteDownloadHandler;
|
use App\Download\Action\Handler\DeleteDownloadHandler;
|
||||||
use App\Download\Action\Handler\DownloadSeasonHandler;
|
|
||||||
use App\Download\Action\Handler\PauseDownloadHandler;
|
use App\Download\Action\Handler\PauseDownloadHandler;
|
||||||
use App\Download\Action\Handler\ResumeDownloadHandler;
|
use App\Download\Action\Handler\ResumeDownloadHandler;
|
||||||
use App\Download\Action\Input\DeleteDownloadInput;
|
use App\Download\Action\Input\DeleteDownloadInput;
|
||||||
@@ -13,8 +12,6 @@ use App\Download\Action\Input\DownloadSeasonInput;
|
|||||||
use App\Download\Action\Input\PauseDownloadInput;
|
use App\Download\Action\Input\PauseDownloadInput;
|
||||||
use App\Download\Action\Input\ResumeDownloadInput;
|
use App\Download\Action\Input\ResumeDownloadInput;
|
||||||
use App\Download\Framework\Repository\DownloadRepository;
|
use App\Download\Framework\Repository\DownloadRepository;
|
||||||
use App\User\Dto\UserPreferencesFactory;
|
|
||||||
use Nihilarr\PTN;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Messenger\MessageBusInterface;
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Monitor\Framework\Controller;
|
namespace App\Monitor\Framework\Controller;
|
||||||
|
|
||||||
use App\Base\Util\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
use App\Monitor\Action\Handler\AddMonitorHandler;
|
use App\Monitor\Action\Handler\AddMonitorHandler;
|
||||||
use App\Monitor\Action\Handler\DeleteMonitorHandler;
|
use App\Monitor\Action\Handler\DeleteMonitorHandler;
|
||||||
use App\Monitor\Action\Input\AddMonitorInput;
|
use App\Monitor\Action\Input\AddMonitorInput;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Torrentio\Framework\Controller;
|
namespace App\Torrentio\Framework\Controller;
|
||||||
|
|
||||||
use App\Base\Util\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
||||||
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
|
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
|
||||||
use App\Torrentio\Action\Input\GetMovieOptionsInput;
|
use App\Torrentio\Action\Input\GetMovieOptionsInput;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Torrentio\Result;
|
namespace App\Torrentio\Result;
|
||||||
|
|
||||||
use App\Base\Util\CountryLanguages;
|
use App\User\Database\CountryLanguages;
|
||||||
use Nihilarr\PTN;
|
use Nihilarr\PTN;
|
||||||
|
|
||||||
class ResultFactory
|
class ResultFactory
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace App\Twig\Components;
|
namespace App\Twig\Components;
|
||||||
|
|
||||||
use Aimeos\Map;
|
use Aimeos\Map;
|
||||||
use App\Base\Util\QualityList;
|
use App\User\Database\QualityList;
|
||||||
use App\User\Framework\Repository\PreferencesRepository;
|
use App\User\Framework\Repository\PreferencesRepository;
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
|
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Base\Util;
|
namespace App\User\Database;
|
||||||
|
|
||||||
class CountryCodes
|
class CountryCodes
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Base\Util;
|
namespace App\User\Database;
|
||||||
|
|
||||||
class CountryLanguages
|
class CountryLanguages
|
||||||
{
|
{
|
||||||
@@ -137,4 +137,13 @@ class CountryLanguages
|
|||||||
|
|
||||||
return $countryLanguages[$countryName] ?? null;
|
return $countryLanguages[$countryName] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function asSelectOptions(): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach (static::$languages as $language) {
|
||||||
|
$result[$language] = $language;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Base\Util;
|
namespace App\User\Database;
|
||||||
|
|
||||||
class ProviderList
|
class ProviderList
|
||||||
{
|
{
|
||||||
@@ -23,4 +23,13 @@ class ProviderList
|
|||||||
{
|
{
|
||||||
return self::$providers;
|
return self::$providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function asSelectOptions(): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach (static::$providers as $provider) {
|
||||||
|
$result[$provider] = $provider;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Base\Util;
|
namespace App\User\Database;
|
||||||
|
|
||||||
class QualityList
|
class QualityList
|
||||||
{
|
{
|
||||||
@@ -100,6 +100,15 @@ class QualityList
|
|||||||
return array_search($key, self::$qualities) ?? null;
|
return array_search($key, self::$qualities) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function asSelectOptions(): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach (array_keys(static::$qualities) as $quality) {
|
||||||
|
$result[$quality] = $quality;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getAsReverseMap(): array
|
public static function getAsReverseMap(): array
|
||||||
{
|
{
|
||||||
$results = [];
|
$results = [];
|
||||||
@@ -4,14 +4,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\User\Framework\Controller\Web;
|
namespace App\User\Framework\Controller\Web;
|
||||||
|
|
||||||
use App\Base\Util\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
use App\Base\Util\CountryLanguages;
|
|
||||||
use App\Base\Util\ProviderList;
|
|
||||||
use App\Base\Util\QualityList;
|
|
||||||
use App\User\Action\Handler\SaveUserDownloadPreferencesHandler;
|
use App\User\Action\Handler\SaveUserDownloadPreferencesHandler;
|
||||||
use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
|
use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
|
||||||
use App\User\Action\Input\SaveUserDownloadPreferencesInput;
|
use App\User\Action\Input\SaveUserDownloadPreferencesInput;
|
||||||
use App\User\Action\Input\SaveUserMediaPreferencesInput;
|
use App\User\Action\Input\SaveUserMediaPreferencesInput;
|
||||||
|
use App\User\Database\CountryLanguages;
|
||||||
|
use App\User\Database\ProviderList;
|
||||||
|
use App\User\Database\QualityList;
|
||||||
|
use App\User\Dto\UserPreferencesFactory;
|
||||||
|
use App\User\Framework\Form\GettingStartedFilterForm;
|
||||||
use App\User\Framework\Repository\PreferencesRepository;
|
use App\User\Framework\Repository\PreferencesRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
@@ -41,6 +43,7 @@ class PreferencesController extends AbstractController
|
|||||||
'qualities' => QualityList::getBaseQualities(),
|
'qualities' => QualityList::getBaseQualities(),
|
||||||
'mediaPreferences' => $mediaPreferences,
|
'mediaPreferences' => $mediaPreferences,
|
||||||
'downloadPreferences' => $downloadPreferences,
|
'downloadPreferences' => $downloadPreferences,
|
||||||
|
'filterForm' => $this->createForm(GettingStartedFilterForm::class, (array) UserPreferencesFactory::createFromUser($this->getUser())),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -72,6 +75,7 @@ class PreferencesController extends AbstractController
|
|||||||
'qualities' => QualityList::getBaseQualities(),
|
'qualities' => QualityList::getBaseQualities(),
|
||||||
'mediaPreferences' => $mediaPreferences,
|
'mediaPreferences' => $mediaPreferences,
|
||||||
'downloadPreferences' => $downloadPreferences,
|
'downloadPreferences' => $downloadPreferences,
|
||||||
|
'filterForm' => $this->createForm(GettingStartedFilterForm::class ?? null),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,30 +5,22 @@ namespace App\User\Framework\Controller\Web;
|
|||||||
use App\User\Action\Command\RegisterUserCommand;
|
use App\User\Action\Command\RegisterUserCommand;
|
||||||
use App\User\Action\Handler\RegisterUserHandler;
|
use App\User\Action\Handler\RegisterUserHandler;
|
||||||
use App\User\Framework\Entity\User;
|
use App\User\Framework\Entity\User;
|
||||||
|
use App\User\Framework\Form\GettingStartedFilterForm;
|
||||||
use App\User\Framework\Form\RegistrationFormType;
|
use App\User\Framework\Form\RegistrationFormType;
|
||||||
use App\User\Framework\Pipeline\GettingStarted\AddPreferencesToDatabase;
|
|
||||||
use App\User\Framework\Pipeline\GettingStarted\GettingStartedInput;
|
|
||||||
use App\User\Framework\Pipeline\GettingStarted\MigrateDatabase;
|
|
||||||
use App\User\Framework\Repository\PreferencesRepository;
|
|
||||||
use App\User\Framework\Repository\UserRepository;
|
use App\User\Framework\Repository\UserRepository;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use League\Pipeline\Pipeline;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
class RegistrationController extends AbstractController
|
class RegistrationController extends AbstractController
|
||||||
{
|
{
|
||||||
public function __construct(private readonly RegisterUserHandler $registerUserHandler,
|
public function __construct(private readonly RegisterUserHandler $registerUserHandler,
|
||||||
private readonly RequestStack $requestStack
|
private readonly RequestStack $requestStack,
|
||||||
)
|
) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/register', name: 'app_register')]
|
#[Route('/register', name: 'app_register')]
|
||||||
public function register(
|
public function register(
|
||||||
@@ -57,7 +49,7 @@ class RegistrationController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route(path: '/getting-started', name: 'app_getting_started')]
|
#[Route(path: '/getting-started', name: 'app_getting_started')]
|
||||||
public function gettingStarted(Request $request, Security $security, UserRepository $userRepository, PreferencesRepository $preferencesRepository, KernelInterface $kernel, LoggerInterface $logger): Response
|
public function gettingStarted(Request $request, Security $security, UserRepository $userRepository): Response
|
||||||
{
|
{
|
||||||
if ((new ArrayCollection($userRepository->findAll()))->count() !== 0) {
|
if ((new ArrayCollection($userRepository->findAll()))->count() !== 0) {
|
||||||
return $this->redirectToRoute('app_index');
|
return $this->redirectToRoute('app_index');
|
||||||
@@ -73,14 +65,42 @@ class RegistrationController extends AbstractController
|
|||||||
password: $form->get('plainPassword')->getData(),
|
password: $form->get('plainPassword')->getData(),
|
||||||
));
|
));
|
||||||
|
|
||||||
$security->login($user->user);
|
$security->login($user->user, 'form_login');
|
||||||
$this->requestStack->getCurrentRequest()->getSession()->set('mercure_alert_topic', 'alerts_' . uniqid());
|
$this->requestStack->getCurrentRequest()->getSession()->set('mercure_alert_topic', 'alerts_' . uniqid());
|
||||||
|
|
||||||
return $this->redirectToRoute('app_index');
|
return $this->redirectToRoute('app_getting_started_filter');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('user/getting-started.html.twig', [
|
return $this->render('user/getting_started/register-user.html.twig', [
|
||||||
'registrationForm' => $form,
|
'registrationForm' => $form,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/getting-started/filter', name: 'app_getting_started_filter')]
|
||||||
|
public function gettingStartedPreferences(Request $request, UserRepository $userRepository): Response
|
||||||
|
{
|
||||||
|
if ((new ArrayCollection($userRepository->findAll()))->count() !== 0) {
|
||||||
|
return $this->redirectToRoute('app_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $this->createForm(GettingStartedFilterForm::class);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
foreach ($form->getData() as $preference => $value) {
|
||||||
|
if (null !== $value) {
|
||||||
|
$this->getUser()->updateUserPreference($preference, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$userRepository->getEntityManager()->flush();
|
||||||
|
return $this->redirectToRoute('app_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render(
|
||||||
|
'user/getting_started/filter.html.twig',
|
||||||
|
[
|
||||||
|
'form' => $form,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace App\User\Framework\EventListener;
|
namespace App\User\Framework\EventListener;
|
||||||
|
|
||||||
use App\Base\ConfigResolver;
|
use App\Base\ConfigResolver;
|
||||||
use App\Base\Util\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
|
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
|
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
|
||||||
|
|||||||
59
src/User/Framework/Form/GettingStartedFilterForm.php
Normal file
59
src/User/Framework/Form/GettingStartedFilterForm.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Framework\Form;
|
||||||
|
|
||||||
|
use Aimeos\Map;
|
||||||
|
use App\User\Database\CountryLanguages;
|
||||||
|
use App\User\Database\ProviderList;
|
||||||
|
use App\User\Database\QualityList;
|
||||||
|
use App\User\Framework\Repository\PreferenceOptionRepository;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class GettingStartedFilterForm extends AbstractType
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly PreferenceOptionRepository $preferenceOptionRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$this->addChoiceField($builder, 'language', CountryLanguages::asSelectOptions());
|
||||||
|
$this->addChoiceField($builder, 'quality', QualityList::asSelectOptions());
|
||||||
|
$this->addChoiceField($builder, 'provider', ProviderList::asSelectOptions());
|
||||||
|
$this->addChoiceField($builder, 'resolution', $this->getPreferenceChoices('resolution'));
|
||||||
|
$this->addChoiceField($builder, 'codec', $this->getPreferenceChoices('codec'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addChoiceField(FormBuilderInterface $builder, string $fieldName, array $choices): void
|
||||||
|
{
|
||||||
|
$question = [
|
||||||
|
'attr' => ['class' => 'w-full text-input mb-4'],
|
||||||
|
'label_attr' => ['class' => 'w-full block font-semibold'],
|
||||||
|
'choices' => $this->addDefaultChoice($choices),
|
||||||
|
];
|
||||||
|
$builder->add($fieldName, ChoiceType::class, $question);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPreferenceChoices(string $preference): array
|
||||||
|
{
|
||||||
|
$options = $this->preferenceOptionRepository->findBy(['preference' => $preference]);
|
||||||
|
$result = [];
|
||||||
|
foreach ($options as $item) {
|
||||||
|
$result[$item->getName()] = $item->getId();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addDefaultChoice(array $choices): iterable
|
||||||
|
{
|
||||||
|
return ['n/a' => null] + $choices;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ class RegistrationFormType extends AbstractType
|
|||||||
'message' => 'Please enter a password',
|
'message' => 'Please enter a password',
|
||||||
]),
|
]),
|
||||||
new Length([
|
new Length([
|
||||||
'min' => 6,
|
'min' => 8,
|
||||||
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
||||||
// max length allowed by Symfony for security reasons
|
// max length allowed by Symfony for security reasons
|
||||||
'max' => 4096,
|
'max' => 4096,
|
||||||
|
|||||||
@@ -86,6 +86,9 @@
|
|||||||
"phpstan.dist.neon"
|
"phpstan.dist.neon"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"spomky-labs/pwa-bundle": {
|
||||||
|
"version": "1.2.5"
|
||||||
|
},
|
||||||
"stof/doctrine-extensions-bundle": {
|
"stof/doctrine-extensions-bundle": {
|
||||||
"version": "1.14",
|
"version": "1.14",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
{{ pwa() }}
|
||||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
{{ pwa() }}
|
||||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
|
|||||||
20
templates/user/getting_started/filter.html.twig
Normal file
20
templates/user/getting_started/filter.html.twig
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'bare.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Getting Started — Torsearch{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<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">
|
||||||
|
<h2 class="text-2xl text-bold text-center text-gray-50">Getting Started</h2>
|
||||||
|
<p class="mb-1">Now let's create your first Filter.</p>
|
||||||
|
{# <p class="mb-2 text-sm">Your filter will be pre-applied to your results, so you're only shown what you want to see. Don't worry, though, you can toggle each filter option afterwards, so you can see the rest of the results.</p>#}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
{{ form_row(form.language) }}
|
||||||
|
{{ form_row(form.quality) }}
|
||||||
|
{{ form_row(form.provider) }}
|
||||||
|
{{ form_row(form.resolution) }}
|
||||||
|
{{ form_row(form.codec) }}
|
||||||
|
<button class="submit-button">Save</button>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
{% block title %}Getting Started — Torsearch{% endblock %}
|
{% block title %}Getting Started — Torsearch{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<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">
|
<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">
|
||||||
<h2 class="text-2xl text-bold text-center text-gray-50">Getting Started</h2>
|
<h2 class="text-2xl text-bold text-center text-gray-50">Getting Started</h2>
|
||||||
<p class="mb-2">Let's get started by creating your first User.</p>
|
<p class="mb-2">Let's get started by creating your first User.</p>
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
{% block title %}Log in — Torsearch{% endblock %}
|
{% block title %}Log in — Torsearch{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<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">
|
<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">
|
||||||
<h2 class="text-xl font-bold">Login</h2>
|
<h2 class="text-xl font-bold">Login</h2>
|
||||||
<form method="post" class="flex flex-col gap-2">
|
<form method="post" class="flex flex-col gap-2">
|
||||||
{% if error %}
|
{% if error %}
|
||||||
|
|||||||
Reference in New Issue
Block a user