Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6da1b65915 | |||
|
|
7c62023e6f | ||
|
|
9e3e2ce15d | ||
|
|
caff0ec71f |
@ -1,10 +1,10 @@
|
||||
# DB Configuration
|
||||
DB_DRIVER=pdo_mysql
|
||||
DB_HOST=myTube-backend-mysql
|
||||
DB_HOST=mytube-backend-mysql
|
||||
DB_PORT=3306
|
||||
DB_USER=myTube
|
||||
DB_USER=mytube
|
||||
DB_PASSWORD=pass
|
||||
DB_NAME=myTube
|
||||
DB_NAME=mytube
|
||||
DB_NAME_LOG=log
|
||||
|
||||
# MyTube Setup
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec build
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec down
|
||||
@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
COMMAND="$@"
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
#LOAD ENV VARIABLES FROM .ENV
|
||||
export $(grep -v '^#' "${SCRIPT_DIR}/../../.env" | xargs)
|
||||
|
||||
#MAC
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
docker compose -f "${SCRIPT_DIR}/../../docker/docker-compose-mac.yml" $COMMAND
|
||||
|
||||
#LINUX
|
||||
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
|
||||
docker compose -f "${SCRIPT_DIR}/../../docker/docker-compose.yml" $COMMAND
|
||||
|
||||
else
|
||||
echo "Dieses Skript wird auf deinem Gerät nicht unterstützt"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#UNSET ENV VARIABLES FROM .ENV
|
||||
unset $(grep -v '^#' "${SCRIPT_DIR}/../../.env" | sed -E 's/(.*)=.*/\1/' | xargs)
|
||||
40
bin/script/firstRun
Executable file
40
bin/script/firstRun
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
PROJECT_DIR=$(realpath $SCRIPT_DIR/../../)
|
||||
ENV_DIR=$(realpath $PROJECT_DIR/../../../)
|
||||
|
||||
source $ENV_DIR/bin/messages
|
||||
source $ENV_DIR/bin/drun
|
||||
|
||||
# Create local config files
|
||||
infomsg '[backend] Creating local config...'
|
||||
cp "$PROJECT_DIR"/config/autoload/monolog.local.php.dist "$PROJECT_DIR"/config/autoload/monolog.local.php
|
||||
cp "$PROJECT_DIR"/config/autoload/doctrine.local.php.dist "$PROJECT_DIR"/config/autoload/doctrine.local.php
|
||||
cp "$PROJECT_DIR"/config/autoload/redis.local.php.dist "$PROJECT_DIR"/config/autoload/redis.local.php
|
||||
successmsg '[backend] Local config done'
|
||||
|
||||
# Install packages
|
||||
infomsg '[backend] Composer install...'
|
||||
drun backend composer install -o
|
||||
successmsg '[backend] Composer install done'
|
||||
|
||||
# Dump autoload
|
||||
infomsg "[backend]: Dump autoload"
|
||||
drun backend composer da
|
||||
successmsg "[backend]: Dump autoload done"
|
||||
|
||||
# Migrate Databases
|
||||
infomsg '[backend] Running migrations...'
|
||||
drun backend composer doctrine migrations:migrate --no-interaction
|
||||
drun backend composer doctrine-log migrations:migrate --no-interaction
|
||||
successmsg '[backend] Migrations done'
|
||||
|
||||
# Seed DB
|
||||
infomsg '[backend] Running seeder...'
|
||||
drun backend composer console init:data
|
||||
drun backend composer console rbac:update
|
||||
successmsg '[backend] Seeding done'
|
||||
|
||||
successmsg '[backend] Initialization script done'
|
||||
|
||||
@ -2,31 +2,19 @@
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
PROJECT_DIR=$(realpath $SCRIPT_DIR/../../)
|
||||
ENV_DIR=$(realpath $PROJECT_DIR/../../)
|
||||
ENV_DIR=$(realpath $PROJECT_DIR/../../../)
|
||||
source $ENV_DIR/bin/messages
|
||||
|
||||
# Check .env file
|
||||
if [ ! -f "$PROJECT_DIR/.env" ]
|
||||
then
|
||||
echo "Create .env file from example..."
|
||||
if [ ! -f "$PROJECT_DIR/.env" ] ; then
|
||||
infomsg "[backend] Creating .env"
|
||||
cp "$PROJECT_DIR/.env.example" "$PROJECT_DIR/.env"
|
||||
echo ".env file created, please change variables and call me again"
|
||||
exit 1
|
||||
successmsg "[backend] Created .env"
|
||||
fi
|
||||
|
||||
# Build and start docker containers
|
||||
$SCRIPT_DIR/exec build
|
||||
$SCRIPT_DIR/exec up -d
|
||||
|
||||
# Source drun
|
||||
source $ENV_DIR/bin/script/drun
|
||||
|
||||
# Install PHP packages
|
||||
drun myTube-backend composer install
|
||||
|
||||
# Migrate databases to current version
|
||||
drun myTube-backend composer dmm
|
||||
drun myTube-backend composer dmlm
|
||||
|
||||
# Insert setup for project after this line
|
||||
drun myTube-backend composer console rbac:update
|
||||
drun myTube-backend composer console init:data
|
||||
# Check docker-compose.yml file
|
||||
if [ ! -f "$PROJECT_DIR/docker/docker-compose.yml" ] ; then
|
||||
infomsg "[backend] Creating docker-compose.yml"
|
||||
cp "$PROJECT_DIR/docker/docker-compose.yml.dist" "$PROJECT_DIR/docker/docker-compose.yml"
|
||||
successmsg "[backend] Creating docker-compose.yml"
|
||||
fi
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec stop
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec up -d
|
||||
39
bin/script/update
Executable file
39
bin/script/update
Executable file
@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
PROJECT_DIR=$(realpath $SCRIPT_DIR/../../)
|
||||
ENV_DIR=$(realpath $PROJECT_DIR/../../../)
|
||||
SYSTEM_ENV_FILE="$PROJECT_DIR/.env"
|
||||
CWD=$(pwd)
|
||||
|
||||
source $ENV_DIR/bin/messages
|
||||
source $ENV_DIR/bin/drun
|
||||
|
||||
# Pull branch in project directory
|
||||
infomsg "[backend]: Git pull"
|
||||
cd "$PROJECT_DIR"
|
||||
git pull
|
||||
successmsg "[backend]: Git pull done"
|
||||
|
||||
# Install packages
|
||||
infomsg '[backend] Composer install...'
|
||||
drun backend composer install -o
|
||||
successmsg '[backend] Composer install done'
|
||||
|
||||
# Dump autoload
|
||||
infomsg "[backend]: Dump autoload"
|
||||
drun backend composer da
|
||||
successmsg "[backend]: Dump autoload done"
|
||||
|
||||
# Migrate Databases
|
||||
infomsg '[backend] Running migrations...'
|
||||
drun backend composer doctrine migrations:migrate --no-interaction
|
||||
drun backend composer doctrine-log migrations:migrate --no-interaction
|
||||
successmsg '[backend] Migrations done'
|
||||
|
||||
# Update permissions
|
||||
infomsg "[backend]: Update roles and permissions"
|
||||
drun backend composer console rbac:update
|
||||
successmsg "[backend]: Update roles and permissions done"
|
||||
|
||||
# Switch back to current working directory
|
||||
cd "$CWD"
|
||||
@ -21,11 +21,13 @@
|
||||
"teewurst\/pipeline": "^3.0",
|
||||
"guzzlehttp\/guzzle": "^7.8",
|
||||
"micilini\/video-stream": "^1.0",
|
||||
"nesbot\/carbon": "^3.0"
|
||||
"nesbot\/carbon": "^3.0",
|
||||
"ext-iconv": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"MyTube\\API\\Console\\": "src\/ApiDomain\/Console\/src",
|
||||
"MyTube\\API\\External\\Analyze\\": "src\/ApiDomain\/External\/Analyze\/src",
|
||||
"MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src",
|
||||
"MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src",
|
||||
"MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src",
|
||||
@ -35,6 +37,7 @@
|
||||
"MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src",
|
||||
"MyTube\\Data\\Business\\": "src\/DataDomain\/Business\/src",
|
||||
"MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src",
|
||||
"MyTube\\Handling\\Analyze\\": "src\/HandlingDomain\/Analyze\/src",
|
||||
"MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src",
|
||||
"MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src",
|
||||
"MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src",
|
||||
@ -78,8 +81,8 @@
|
||||
"scripts": {
|
||||
"dmg": "php bin\/doctrine-migrations.php migrations:generate",
|
||||
"dmm": "php bin\/doctrine-migrations.php migrations:migrate --no-interaction",
|
||||
"dmlg": "php bin\/doctrine-migrations-log.php migrations:generate",
|
||||
"dmlm": "php bin\/doctrine-migrations-log.php migrations:migrate --no-interaction",
|
||||
"doctrine": "php bin\/doctrine-migrations.php",
|
||||
"doctrine-log": "php bin\/doctrine-migrations-log.php",
|
||||
"console": "php bin\/console.php",
|
||||
"createApi": "php bin\/createApi.php",
|
||||
"createPipeline": "php bin\/createPipeline.php",
|
||||
@ -98,6 +101,7 @@
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"MyTube\\API\\External\\Analyze\\": "src\/ApiDomain\/External\/Analyze\/src",
|
||||
"MyTube\\API\\External\\Authentication\\": "src\/ApiDomain\/External\/Authentication\/src",
|
||||
"MyTube\\API\\External\\Health\\": "src\/ApiDomain\/External\/Health\/src",
|
||||
"MyTube\\API\\External\\Tag\\": "src\/ApiDomain\/External\/Tag\/src",
|
||||
@ -107,6 +111,7 @@
|
||||
"MyTube\\API\\External\\VideoList\\": "src\/ApiDomain\/External\/VideoList\/src",
|
||||
"MyTube\\Data\\Business\\": "src\/DataDomain\/Business\/src",
|
||||
"MyTube\\Data\\Log\\": "src\/DataDomain\/Log\/src",
|
||||
"MyTube\\Handling\\Analyze\\": "src\/HandlingDomain\/Analyze\/src",
|
||||
"MyTube\\Handling\\Registration\\": "src\/HandlingDomain\/Registration\/src",
|
||||
"MyTube\\Handling\\Role\\": "src\/HandlingDomain\/Role\/src",
|
||||
"MyTube\\Handling\\Tag\\": "src\/HandlingDomain\/Tag\/src",
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
"teewurst/pipeline": "^3.0",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"micilini/video-stream": "^1.0",
|
||||
"nesbot/carbon": "^3.0"
|
||||
"nesbot/carbon": "^3.0",
|
||||
"ext-iconv": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@ -51,8 +52,8 @@
|
||||
"scripts": {
|
||||
"dmg": "php bin/doctrine-migrations.php migrations:generate",
|
||||
"dmm": "php bin/doctrine-migrations.php migrations:migrate --no-interaction",
|
||||
"dmlg": "php bin/doctrine-migrations-log.php migrations:generate",
|
||||
"dmlm": "php bin/doctrine-migrations-log.php migrations:migrate --no-interaction",
|
||||
"doctrine": "php bin/doctrine-migrations.php",
|
||||
"doctrine-log": "php bin/doctrine-migrations-log.php",
|
||||
"console": "php bin/console.php",
|
||||
"createApi": "php bin/createApi.php",
|
||||
"createPipeline": "php bin/createPipeline.php",
|
||||
|
||||
@ -3,26 +3,9 @@
|
||||
return [
|
||||
'api' => [
|
||||
'keys' => [
|
||||
'myTube' => $_ENV['HOMEPAGE_API_KEY'],
|
||||
'notification' => $_ENV['NOTIFICATION_API_KEY'],
|
||||
],
|
||||
|
||||
'services' => [
|
||||
'myTube' => [
|
||||
'host' => 'myTube-backend-nginx',
|
||||
'apis' => [
|
||||
|
||||
]
|
||||
],
|
||||
'notification' => [
|
||||
'host' => 'notification-backend-nginx',
|
||||
'apis' => [
|
||||
'send-mail' => [
|
||||
'path' => '/api/mail/send',
|
||||
'method' => 'POST'
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@ -54,6 +54,7 @@ $aggregator = new ConfigAggregator([
|
||||
\MyTube\Infrastructure\Session\ConfigProvider::class,
|
||||
|
||||
// HandlingDomain
|
||||
\MyTube\Handling\Analyze\ConfigProvider::class,
|
||||
\MyTube\Handling\User\ConfigProvider::class,
|
||||
\MyTube\Handling\UserSession\ConfigProvider::class,
|
||||
\MyTube\Handling\Registration\ConfigProvider::class,
|
||||
@ -70,6 +71,7 @@ $aggregator = new ConfigAggregator([
|
||||
\MyTube\API\External\Health\ConfigProvider::class,
|
||||
\MyTube\API\External\User\ConfigProvider::class,
|
||||
\MyTube\API\External\Authentication\ConfigProvider::class,
|
||||
\MyTube\API\External\Analyze\ConfigProvider::class,
|
||||
\MyTube\API\External\Video\ConfigProvider::class,
|
||||
\MyTube\API\External\VideoList\ConfigProvider::class,
|
||||
\MyTube\API\External\Tag\ConfigProvider::class,
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
version: '3'
|
||||
networks:
|
||||
myTube:
|
||||
external: true
|
||||
|
||||
services:
|
||||
myTube-backend-mysql:
|
||||
image: myTube-backend-mysql
|
||||
networks:
|
||||
- myTube
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/mysql/dockerfile
|
||||
volumes:
|
||||
- /Users/flo/dev/backend/myTube/var/db:/var/lib/mysql:z
|
||||
environment:
|
||||
MYSQL_USER: ${DB_USER}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
ports:
|
||||
- 3306:3306
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
myTube-backend-app:
|
||||
image: myTube-backend-app
|
||||
networks:
|
||||
- myTube
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/php/dockerfile
|
||||
volumes:
|
||||
- /Users/flo/dev/backend/myTube/:/var/www/html:z
|
||||
ports:
|
||||
- 9000:9000
|
||||
depends_on:
|
||||
myTube-backend-mysql:
|
||||
condition: service_healthy
|
||||
|
||||
myTube-backend-nginx:
|
||||
image: myTube-backend-nginx
|
||||
networks:
|
||||
- myTube
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/nginx/dockerfile
|
||||
ports:
|
||||
- 8080:80
|
||||
depends_on:
|
||||
- myTube-backend-app
|
||||
@ -1,4 +1,3 @@
|
||||
version: '3'
|
||||
networks:
|
||||
mytube:
|
||||
external: true
|
||||
@ -45,7 +44,9 @@ services:
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/nginx/dockerfile
|
||||
ports:
|
||||
- 8080:80
|
||||
labels:
|
||||
- "traefik.http.routers.backend.rule=(Host(`mytube.srv`) || Host(`192.168.152.60`)) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.backend.entrypoints=websecure"
|
||||
- "traefik.http.routers.backend.tls.certresolver=le"
|
||||
depends_on:
|
||||
- mytube-backend-app
|
||||
@ -1,4 +1,4 @@
|
||||
CREATE DATABASE IF NOT EXISTS `log`;
|
||||
CREATE DATABASE IF NOT EXISTS `myTube`;
|
||||
CREATE DATABASE IF NOT EXISTS `mytube`;
|
||||
|
||||
GRANT ALL PRIVILEGES on *.* to 'myTube'@'%';
|
||||
GRANT ALL PRIVILEGES on *.* to 'mytube'@'%';
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use MyTube\API\Console\Command\AnalyzeTagsCommand;
|
||||
use MyTube\API\Console\Command\AnalyzeVideoTitlesCommand;
|
||||
use MyTube\API\Console\Command\InitializeDataCommand;
|
||||
use MyTube\API\Console\Command\RbacUpdateCommand;
|
||||
@ -11,5 +12,6 @@ return [
|
||||
RbacUpdateCommand::class,
|
||||
AnalyzeVideoTitlesCommand::class,
|
||||
ReadUntaggedVideosCommand::class,
|
||||
AnalyzeTagsCommand::class,
|
||||
]
|
||||
];
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use MyTube\API\Console\Command\AnalyzeTagsCommand;
|
||||
use MyTube\API\Console\Command\AnalyzeVideoTitlesCommand;
|
||||
use MyTube\API\Console\Command\InitializeDataCommand;
|
||||
use MyTube\API\Console\Command\RbacUpdateCommand;
|
||||
@ -11,6 +12,7 @@ return [
|
||||
InitializeDataCommand::class => AutoWiringFactory::class,
|
||||
RbacUpdateCommand::class => AutoWiringFactory::class,
|
||||
AnalyzeVideoTitlesCommand::class => AutoWiringFactory::class,
|
||||
AnalyzeTagsCommand::class => AutoWiringFactory::class,
|
||||
ReadUntaggedVideosCommand::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
|
||||
133
src/ApiDomain/Console/src/Command/AnalyzeTagsCommand.php
Normal file
133
src/ApiDomain/Console/src/Command/AnalyzeTagsCommand.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace MyTube\API\Console\Command;
|
||||
|
||||
use MyTube\Data\Business\Entity\Tag;
|
||||
use MyTube\Data\Business\Entity\Video;
|
||||
use MyTube\Data\Business\Manager\MyTubeEntityManager;
|
||||
use MyTube\Data\Business\Repository\VideoRepository;
|
||||
use MyTube\Handling\Tag\Rule\IsTagSubstringRule;
|
||||
use MyTube\Handling\Video\Analyzer\VideoDurationAnalyzer;
|
||||
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
|
||||
use MyTube\Infrastructure\Logging\Logger\Logger;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use function Webmozart\Assert\Tests\StaticAnalysis\length;
|
||||
|
||||
#[AsCommand(name: 'analyze:tags', description: 'Analyzes video titles and add tags')]
|
||||
class AnalyzeTagsCommand extends Command
|
||||
{
|
||||
private readonly VideoRepository $videoRepository;
|
||||
|
||||
public function __construct(
|
||||
private readonly MyTubeEntityManager $entityManager,
|
||||
private readonly IsTagSubstringRule $isTagSubstringRule,
|
||||
private readonly Logger $logger,
|
||||
) {
|
||||
parent::__construct($this->getName());
|
||||
|
||||
$this->videoRepository = $this->entityManager->getRepository(Video::class);
|
||||
}
|
||||
|
||||
protected function execute(
|
||||
InputInterface $input,
|
||||
OutputInterface $output
|
||||
): int {
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
try {
|
||||
$videos = $this->videoRepository->findAll();
|
||||
|
||||
/** @var Video $video */
|
||||
foreach ($videos as $video) {
|
||||
$comments[] = $video->getTitle();
|
||||
}
|
||||
|
||||
|
||||
// Normalisierte Kommentare
|
||||
$normalized_comments = array_map([$this, 'normalize'], $comments);
|
||||
|
||||
// Tokenisierung und Wortzählung
|
||||
$word_counts = [];
|
||||
foreach ($normalized_comments as $comment) {
|
||||
$words = explode(' ', $comment);
|
||||
foreach ($words as $word) {
|
||||
if ($word) {
|
||||
if (!isset($word_counts[$word])) {
|
||||
$word_counts[$word] = 0;
|
||||
}
|
||||
$word_counts[$word]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Konsolidierung der Wörter unter Berücksichtigung von Tippfehlern
|
||||
$corrected_word_counts = [];
|
||||
$dictionary = array_keys($word_counts);
|
||||
foreach ($word_counts as $word => $count) {
|
||||
$correct_word = $this->correct_typo($word, $dictionary);
|
||||
if (!isset($corrected_word_counts[$correct_word])) {
|
||||
$corrected_word_counts[$correct_word] = 0;
|
||||
}
|
||||
$corrected_word_counts[$correct_word] += $count;
|
||||
}
|
||||
|
||||
// Sortieren nach Häufigkeit
|
||||
arsort($corrected_word_counts);
|
||||
$corrected_word_counts = array_reverse($corrected_word_counts);
|
||||
|
||||
// Ausgabe der häufigsten Wörter
|
||||
foreach ($corrected_word_counts as $word => $count) {
|
||||
if ($count > 3 && !$this->isTagSubstringRule->appliesTo($word)) {
|
||||
echo $word . ": " . $count . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$io->success('OK!');
|
||||
} catch (\Throwable $e) {
|
||||
$io->error($e->getMessage());
|
||||
$io->error($e->getTraceAsString());
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
function normalize($text) {
|
||||
// Kleinbuchstaben
|
||||
$text = mb_strtolower($text);
|
||||
// Akzente entfernen
|
||||
$text = iconv('UTF-8', 'ASCII//TRANSLIT', $text);
|
||||
// Interpunktion entfernen
|
||||
$text = preg_replace("/[^a-z\s]/", "", $text);
|
||||
// Trimmen
|
||||
$text = trim($text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
|
||||
// Tippfehlerkorrektur mit Levenshtein-Distanz
|
||||
function correct_typo($word, $dictionary) {
|
||||
$closest_word = $word;
|
||||
$shortest_distance = -1;
|
||||
foreach ($dictionary as $dict_word) {
|
||||
$lev = levenshtein($word, $dict_word);
|
||||
if ($lev == 0) {
|
||||
$closest_word = $word;
|
||||
$shortest_distance = 0;
|
||||
break;
|
||||
}
|
||||
if ($lev <= 2 && ($lev < $shortest_distance || $shortest_distance < 0)) {
|
||||
$closest_word = $dict_word;
|
||||
$shortest_distance = $lev;
|
||||
}
|
||||
}
|
||||
return $closest_word;
|
||||
}
|
||||
}
|
||||
25
src/ApiDomain/External/Analyze/config/routes.php
vendored
Normal file
25
src/ApiDomain/External/Analyze/config/routes.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use MyTube\API\External\Analyze\Handler\AnalyzeVideosHandler;
|
||||
use MyTube\API\External\Analyze\Handler\ReadVideoListHandler;
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'analyze.analyze-videos',
|
||||
'path' => '/api/analyze/analyze-videos[/]',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
AnalyzeVideosHandler::class,
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'analyze.read-video-list',
|
||||
'path' => '/api/analyze/read-video-list[/]',
|
||||
'allowed_methods' => ['POST'],
|
||||
'middleware' => [
|
||||
ReadVideoListHandler::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
21
src/ApiDomain/External/Analyze/config/service_manager.php
vendored
Normal file
21
src/ApiDomain/External/Analyze/config/service_manager.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use MyTube\API\External\Analyze\Handler\AnalyzeVideosHandler;
|
||||
use MyTube\API\External\Analyze\Handler\ReadVideoListHandler;
|
||||
use MyTube\API\External\Analyze\ResponseFormatter\AnalyzeVideosResponseFormatter;
|
||||
use MyTube\API\External\Analyze\ResponseFormatter\ReadVideoListResponseFormatter;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
// Handler
|
||||
AnalyzeVideosHandler::class => AutoWiringFactory::class,
|
||||
ReadVideoListHandler::class => AutoWiringFactory::class,
|
||||
|
||||
// Response Formatter
|
||||
AnalyzeVideosResponseFormatter::class => AutoWiringFactory::class,
|
||||
ReadVideoListResponseFormatter::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
16
src/ApiDomain/External/Analyze/src/ConfigProvider.php
vendored
Normal file
16
src/ApiDomain/External/Analyze/src/ConfigProvider.php
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Analyze;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . './../config/service_manager.php',
|
||||
'routes' => require __DIR__ . '/./../config/routes.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
34
src/ApiDomain/External/Analyze/src/Handler/AnalyzeVideosHandler.php
vendored
Normal file
34
src/ApiDomain/External/Analyze/src/Handler/AnalyzeVideosHandler.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Analyze\Handler;
|
||||
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandHandler;
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandBuilder;
|
||||
use MyTube\API\External\Analyze\ResponseFormatter\AnalyzeVideosResponseFormatter;
|
||||
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
|
||||
use MyTube\Infrastructure\Response\SuccessResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class AnalyzeVideosHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AnalyzeVideosCommandHandler $analyzeVideosCommandHandler,
|
||||
private readonly AnalyzeVideosCommandBuilder $analyzeVideosCommandBuilder,
|
||||
private readonly AnalyzeVideosResponseFormatter $responseFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
|
||||
|
||||
$analyzeVideosCommand = $this->analyzeVideosCommandBuilder->build();
|
||||
$result = $this->analyzeVideosCommandHandler->execute($analyzeVideosCommand);
|
||||
|
||||
return new SuccessResponse($this->responseFormatter->format($result));
|
||||
}
|
||||
}
|
||||
39
src/ApiDomain/External/Analyze/src/Handler/ReadVideoListHandler.php
vendored
Normal file
39
src/ApiDomain/External/Analyze/src/Handler/ReadVideoListHandler.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Analyze\Handler;
|
||||
|
||||
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
|
||||
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
|
||||
use MyTube\API\External\Analyze\ResponseFormatter\ReadVideoListResponseFormatter;
|
||||
use MyTube\Infrastructure\Request\Middleware\AnalyzeBodyMiddleware;
|
||||
use MyTube\Infrastructure\Response\SuccessResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class ReadVideoListHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ReadVideoListQueryHandler $readVideoListQueryHandler,
|
||||
private readonly ReadVideoListQueryBuilder $readVideoListQueryBuilder,
|
||||
private readonly ReadVideoListResponseFormatter $responseFormatter,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$data = $request->getAttribute(AnalyzeBodyMiddleware::JSON_DATA);
|
||||
|
||||
$readVideoListQuery = $this->readVideoListQueryBuilder->build(
|
||||
$data['query'] ?? null,
|
||||
$data['page'],
|
||||
$data['perPage'],
|
||||
$data['onlyTagless'] ?? false,
|
||||
);
|
||||
$result = $this->readVideoListQueryHandler->execute($readVideoListQuery);
|
||||
|
||||
return new SuccessResponse($this->responseFormatter->format($result));
|
||||
}
|
||||
}
|
||||
50
src/ApiDomain/External/Analyze/src/ResponseFormatter/AnalyzeVideosResponseFormatter.php
vendored
Normal file
50
src/ApiDomain/External/Analyze/src/ResponseFormatter/AnalyzeVideosResponseFormatter.php
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Analyze\ResponseFormatter;
|
||||
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandResult;
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\Model\VideoChangedModel;
|
||||
|
||||
class AnalyzeVideosResponseFormatter
|
||||
{
|
||||
public function format(AnalyzeVideosCommandResult $analyzeVideosCommandResult): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
/** @var VideoChangedModel $changedVideo */
|
||||
foreach ($analyzeVideosCommandResult->getChangedVideos() as $changedVideo) {
|
||||
$tags = [];
|
||||
$newTags = [];
|
||||
$video = $changedVideo->getVideo();
|
||||
|
||||
foreach ($changedVideo->getNewTags() as $tag) {
|
||||
$newTags[] = [
|
||||
'id' => $tag->getId(),
|
||||
'description' => $tag->getDescription(),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($video->getTags() as $tag) {
|
||||
$tags[] = [
|
||||
'id' => $tag->getId(),
|
||||
'description' => $tag->getDescription(),
|
||||
];
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'video' => [
|
||||
'id' => $video->getId(),
|
||||
'title' => $video->getTitle(),
|
||||
'duration' => gmdate("H:i:s", $video->getDuration()),
|
||||
'tags' => $tags,
|
||||
],
|
||||
'newTags' => $newTags,
|
||||
'newDuration' => $changedVideo->isNewDuration()
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
45
src/ApiDomain/External/Analyze/src/ResponseFormatter/ReadVideoListResponseFormatter.php
vendored
Normal file
45
src/ApiDomain/External/Analyze/src/ResponseFormatter/ReadVideoListResponseFormatter.php
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Analyze\ResponseFormatter;
|
||||
|
||||
use MyTube\Data\Business\Entity\Tag;
|
||||
use MyTube\Data\Business\Entity\Video;
|
||||
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryResult;
|
||||
|
||||
class ReadVideoListResponseFormatter
|
||||
{
|
||||
public function format(ReadVideoListQueryResult $queryResult): array
|
||||
{
|
||||
$paginator = $queryResult->getPaginator();
|
||||
$videos = $paginator->getIterator();
|
||||
|
||||
$items = [];
|
||||
|
||||
/** @var Video $video */
|
||||
foreach ($videos as $video) {
|
||||
$tags = [];
|
||||
|
||||
/** @var Tag $tag */
|
||||
foreach ($video->getTags() as $tag) {
|
||||
$tags[] = [
|
||||
'id' => $tag->getId(),
|
||||
'description' => $tag->getDescription()
|
||||
];
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'title' => $video->getTitle(),
|
||||
'id' => $video->getId(),
|
||||
'duration' => $video->getDuration() === null ? 'n. def' : gmdate("H:i:s", $video->getDuration()),
|
||||
'tags' => $tags
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'total' => $paginator->count(),
|
||||
'items' => $items,
|
||||
];
|
||||
}
|
||||
}
|
||||
9
src/ApiDomain/External/Tag/config/routes.php
vendored
9
src/ApiDomain/External/Tag/config/routes.php
vendored
@ -3,6 +3,7 @@
|
||||
use MyTube\API\External\Tag\Handler\AddAliasHandler;
|
||||
use MyTube\API\External\Tag\Handler\CreateHandler;
|
||||
use MyTube\API\External\Tag\Handler\ReadDetailsHandler;
|
||||
use MyTube\API\External\Tag\Handler\ReadThumbnailHandler;
|
||||
use MyTube\API\External\Tag\Handler\ReadVideoListHandler;
|
||||
|
||||
return [
|
||||
@ -38,4 +39,12 @@ return [
|
||||
ReadVideoListHandler::class,
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'tag.thumbnail',
|
||||
'path' => '/api/tag/thumbnail/:tagUuid[/]',
|
||||
'allowed_methods' => ['GET'],
|
||||
'middleware' => [
|
||||
ReadThumbnailHandler::class,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
use MyTube\API\External\Tag\Handler\AddAliasHandler;
|
||||
use MyTube\API\External\Tag\Handler\CreateHandler;
|
||||
use MyTube\API\External\Tag\Handler\ReadDetailsHandler;
|
||||
use MyTube\API\External\Tag\Handler\ReadThumbnailHandler;
|
||||
use MyTube\API\External\Tag\Handler\ReadVideoListHandler;
|
||||
use MyTube\API\External\Tag\ResponseFormatter\AddAliasResponseFormatter;
|
||||
use MyTube\API\External\Tag\ResponseFormatter\CreateResponseFormatter;
|
||||
@ -17,6 +18,7 @@ return [
|
||||
CreateHandler::class => AutoWiringFactory::class,
|
||||
ReadDetailsHandler::class => AutoWiringFactory::class,
|
||||
ReadVideoListHandler::class => AutoWiringFactory::class,
|
||||
ReadThumbnailHandler::class => AutoWiringFactory::class,
|
||||
|
||||
// Response Formatter
|
||||
AddAliasResponseFormatter::class => AutoWiringFactory::class,
|
||||
|
||||
58
src/ApiDomain/External/Tag/src/Handler/ReadThumbnailHandler.php
vendored
Normal file
58
src/ApiDomain/External/Tag/src/Handler/ReadThumbnailHandler.php
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Tag\Handler;
|
||||
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Laminas\Diactoros\Response\TextResponse;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadThumbnail\ReadThumbnailQueryBuilder;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadThumbnail\ReadThumbnailQueryHandler;
|
||||
use MyTube\Infrastructure\Exception\Exception\MyTubeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Throwable;
|
||||
|
||||
class ReadThumbnailHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ReadThumbnailQueryHandler $readThumbnailQueryHandler,
|
||||
private readonly ReadThumbnailQueryBuilder $readThumbnailQueryBuilder,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$tagUuid = $request->getAttribute('tagUuid') ?? null;
|
||||
|
||||
if ($tagUuid === null) {
|
||||
throw new MyTubeException('No tagUuid provided');
|
||||
}
|
||||
|
||||
try {
|
||||
$readThumbnailQuery = $this->readThumbnailQueryBuilder->build(
|
||||
Uuid::fromString($tagUuid)
|
||||
);
|
||||
$result = $this->readThumbnailQueryHandler->execute($readThumbnailQuery);
|
||||
|
||||
$thumbnailVideo = $result->getThumbnailVideo();
|
||||
if ($thumbnailVideo === null) {
|
||||
throw new MyTubeException('No thumbnail video for tag');
|
||||
}
|
||||
|
||||
$filePath = $thumbnailVideo->getDirectoryPath() . 'thumbnail.png';
|
||||
if (!file_exists($filePath)) {
|
||||
throw new MyTubeException('Thumbnail file does not exist');
|
||||
}
|
||||
|
||||
$fileContent = file_get_contents($filePath);
|
||||
$response = new TextResponse($fileContent);
|
||||
return $response->withHeader('Content-Type', 'image/png');
|
||||
|
||||
} catch (Throwable $exception) {
|
||||
return new JsonResponse('Not Found', 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/ApiDomain/External/Tag/src/ResponseFormatter/ReadThumbnailResponseFormatter.php
vendored
Normal file
15
src/ApiDomain/External/Tag/src/ResponseFormatter/ReadThumbnailResponseFormatter.php
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\API\External\Tag\ResponseFormatter;
|
||||
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadThumbnail\ReadThumbnailQueryResult;
|
||||
|
||||
class ReadThumbnailResponseFormatter
|
||||
{
|
||||
public function format(ReadThumbnailQueryResult $readThumbnailQueryResult): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,6 @@ class ReadListHandler implements RequestHandlerInterface
|
||||
$data['query'] ?? null,
|
||||
$data['page'],
|
||||
$data['perPage'],
|
||||
$data['onlyTagless'] ?? false,
|
||||
);
|
||||
$result = $this->readListQueryHandler->execute($readListQuery);
|
||||
|
||||
|
||||
@ -9,16 +9,20 @@ class TagRepository extends EntityRepository {
|
||||
?string $query,
|
||||
): array
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder('t');
|
||||
$queryBuilder = $this->createQueryBuilder('t')
|
||||
->leftJoin('t.videos', 'v')
|
||||
->groupBy('t.id')
|
||||
->select('t, COUNT(v.id) as HIDDEN video_count')
|
||||
->orderBy('video_count', 'DESC');
|
||||
|
||||
if ($query !== null) {
|
||||
$query = '%'.$query.'%';
|
||||
|
||||
$queryBuilder
|
||||
->where('t.description like :query')
|
||||
->where('t.description LIKE :query')
|
||||
->setParameter('query', $query);
|
||||
}
|
||||
|
||||
return $queryBuilder->getQuery()->execute();
|
||||
return $queryBuilder->getQuery()->getResult();
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,6 @@ class VideoRepository extends EntityRepository {
|
||||
?string $query,
|
||||
int $page,
|
||||
int $perPage,
|
||||
bool $onlyTagless,
|
||||
?Tag $tag = null,
|
||||
?string $orderBy = null,
|
||||
string $orderDirection = 'desc'
|
||||
@ -43,7 +42,7 @@ class VideoRepository extends EntityRepository {
|
||||
->setParameter('tagId', $tag->getId(), UuidBinaryOrderedTimeType::NAME);
|
||||
}
|
||||
|
||||
if ($onlyTagless) {
|
||||
if (false) { //only tagless
|
||||
$queryBuilder = $queryBuilder
|
||||
->andWhere( $queryBuilder->expr()->isNull('t.id') );
|
||||
}
|
||||
|
||||
26
src/HandlingDomain/Analyze/config/service_manager.php
Normal file
26
src/HandlingDomain/Analyze/config/service_manager.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandHandler;
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\AnalyzeVideosCommandBuilder;
|
||||
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
|
||||
use MyTube\Handling\Analyze\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
|
||||
use MyTube\Handling\Analyze\Repository\AnalyzeVideoRepository;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
use Reinfi\DependencyInjection\Factory\InjectionFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
/// Repository
|
||||
AnalyzeVideoRepository::class => AutoWiringFactory::class,
|
||||
|
||||
/// CQRS
|
||||
// AnalyzeVideos
|
||||
AnalyzeVideosCommandBuilder::class => AutoWiringFactory::class,
|
||||
AnalyzeVideosCommandHandler::class => AutoWiringFactory::class,
|
||||
// Read Video List
|
||||
ReadVideoListQueryBuilder::class => AutoWiringFactory::class,
|
||||
ReadVideoListQueryHandler::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
15
src/HandlingDomain/Analyze/src/ConfigProvider.php
Normal file
15
src/HandlingDomain/Analyze/src/ConfigProvider.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => require __DIR__ . './../config/service_manager.php',
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
|
||||
|
||||
class AnalyzeVideosCommand
|
||||
{
|
||||
public function __construct(
|
||||
#TODO
|
||||
) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
|
||||
|
||||
class AnalyzeVideosCommandBuilder
|
||||
{
|
||||
public function build(
|
||||
#TODO
|
||||
): AnalyzeVideosCommand {
|
||||
return new AnalyzeVideosCommand(
|
||||
#TODO
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
|
||||
|
||||
use MyTube\Data\Business\Entity\Video;
|
||||
use MyTube\Data\Business\Manager\MyTubeEntityManager;
|
||||
use MyTube\Data\Business\Repository\VideoRepository;
|
||||
use MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\Model\VideoChangedModel;
|
||||
use MyTube\Handling\Video\Analyzer\VideoDurationAnalyzer;
|
||||
use MyTube\Handling\Video\Analyzer\VideoTitleAnalyzer;
|
||||
|
||||
class AnalyzeVideosCommandHandler
|
||||
{
|
||||
private readonly VideoRepository $videoRepository;
|
||||
|
||||
public function __construct(
|
||||
private readonly MyTubeEntityManager $entityManager,
|
||||
private readonly VideoTitleAnalyzer $titleAnalyzer,
|
||||
private readonly VideoDurationAnalyzer $durationAnalyzer,
|
||||
) {
|
||||
$this->videoRepository = $this->entityManager->getRepository(Video::class);
|
||||
}
|
||||
|
||||
public function execute(AnalyzeVideosCommand $analyzeVideosCommand): AnalyzeVideosCommandResult
|
||||
{
|
||||
$videos = $this->videoRepository->findAll();
|
||||
$changedVideos = [];
|
||||
|
||||
/** @var Video $video */
|
||||
foreach ($videos as $video) {
|
||||
$newTags = $this->titleAnalyzer->analyze($video);
|
||||
$newDuration = $this->durationAnalyzer->analyze($video);
|
||||
|
||||
if (count($newTags) > 0 || $newDuration) {
|
||||
$changedVideos[] = new VideoChangedModel($video, $newTags, $newDuration);
|
||||
$this->entityManager->persist($video);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
return new AnalyzeVideosCommandResult($changedVideos);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos;
|
||||
|
||||
class AnalyzeVideosCommandResult
|
||||
{
|
||||
public function __construct(
|
||||
private array $changedVideos
|
||||
) {
|
||||
}
|
||||
|
||||
public function getChangedVideos(): array
|
||||
{
|
||||
return $this->changedVideos;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Command\AnalyzeVideos\Model;
|
||||
|
||||
use MyTube\Data\Business\Entity\Video;
|
||||
|
||||
class VideoChangedModel
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Video $video,
|
||||
private readonly ?array $newTags = null,
|
||||
private readonly bool $newDuration = false
|
||||
) {
|
||||
}
|
||||
|
||||
public function getVideo(): Video
|
||||
{
|
||||
return $this->video;
|
||||
}
|
||||
|
||||
public function getNewTags(): ?array
|
||||
{
|
||||
return $this->newTags;
|
||||
}
|
||||
|
||||
public function isNewDuration(): bool
|
||||
{
|
||||
return $this->newDuration;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
|
||||
|
||||
class ReadVideoListQuery
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ?string $query,
|
||||
private readonly int $page,
|
||||
private readonly int $perPage,
|
||||
private readonly bool $onlyTagless,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getQuery(): ?string
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
public function getPage(): int
|
||||
{
|
||||
return $this->page;
|
||||
}
|
||||
|
||||
public function getPerPage(): int
|
||||
{
|
||||
return $this->perPage;
|
||||
}
|
||||
|
||||
public function getOnlyTagless(): bool
|
||||
{
|
||||
return $this->onlyTagless;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
|
||||
|
||||
class ReadVideoListQueryBuilder
|
||||
{
|
||||
public function build(
|
||||
?string $query,
|
||||
int $page,
|
||||
int $perPage,
|
||||
bool $onlyTagless,
|
||||
): ReadVideoListQuery {
|
||||
return new ReadVideoListQuery(
|
||||
$query,
|
||||
$page,
|
||||
$perPage,
|
||||
$onlyTagless,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
|
||||
|
||||
|
||||
use MyTube\Handling\Analyze\Repository\AnalyzeVideoRepository;
|
||||
|
||||
class ReadVideoListQueryHandler
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AnalyzeVideoRepository $analyzeVideoRepository
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(ReadVideoListQuery $readVideoListQuery): ReadVideoListQueryResult
|
||||
{
|
||||
return new ReadVideoListQueryResult(
|
||||
$this->analyzeVideoRepository->findByFilter(
|
||||
query: $readVideoListQuery->getQuery(),
|
||||
page: $readVideoListQuery->getPage(),
|
||||
perPage: $readVideoListQuery->getPerPage(),
|
||||
onlyTagless: $readVideoListQuery->getOnlyTagless()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Handler\Query\ReadVideoList;
|
||||
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
|
||||
class ReadVideoListQueryResult
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Paginator $paginator
|
||||
) {
|
||||
}
|
||||
|
||||
public function getPaginator(): Paginator
|
||||
{
|
||||
return $this->paginator;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Analyze\Repository;
|
||||
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use MyTube\Data\Business\Entity\Video;
|
||||
use MyTube\Data\Business\Manager\MyTubeEntityManager;
|
||||
|
||||
class AnalyzeVideoRepository
|
||||
{
|
||||
private const FIELD_MAP = [
|
||||
'duration' => 'v.duration',
|
||||
'title' => 'v.title',
|
||||
'createdAt' => 'v.createdAt'
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly MyTubeEntityManager $entityManager
|
||||
) {
|
||||
}
|
||||
|
||||
public function findByFilter(
|
||||
?string $query,
|
||||
int $page,
|
||||
int $perPage,
|
||||
bool $onlyTagless,
|
||||
?string $orderBy = null,
|
||||
string $orderDirection = 'asc'
|
||||
): Paginator
|
||||
{
|
||||
$orderBy = self::FIELD_MAP[$orderBy] ?? self::FIELD_MAP['title'];
|
||||
|
||||
$queryBuilder = $this->entityManager->createQueryBuilder()
|
||||
->select('v')
|
||||
->from(Video::class, 'v')
|
||||
->leftJoin('v.tags', 't');
|
||||
|
||||
if ($query !== null) {
|
||||
$query = '%'.$query.'%';
|
||||
$queryBuilder = $queryBuilder
|
||||
->where('v.title like :query')
|
||||
->orWhere('t.description like :query')
|
||||
->setParameter('query', $query);
|
||||
}
|
||||
|
||||
if ($onlyTagless) {
|
||||
$queryBuilder = $queryBuilder
|
||||
->andWhere( $queryBuilder->expr()->isNull('t.id') );
|
||||
}
|
||||
|
||||
$queryBuilder->orderBy($orderBy,$orderDirection);
|
||||
|
||||
$queryBuilder->setFirstResult($perPage * ($page - 1));
|
||||
$queryBuilder->setMaxResults($perPage);
|
||||
|
||||
return new Paginator($queryBuilder->getQuery());
|
||||
}
|
||||
}
|
||||
@ -8,8 +8,11 @@ use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandBuilder;
|
||||
use MyTube\Handling\Tag\Handler\Command\Create\CreateCommandHandler;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryBuilder;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadDetails\ReadDetailsQueryHandler;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadThumbnail\ReadThumbnailQueryBuilder;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadThumbnail\ReadThumbnailQueryHandler;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryBuilder;
|
||||
use MyTube\Handling\Tag\Handler\Query\ReadVideoList\ReadVideoListQueryHandler;
|
||||
use MyTube\Handling\Tag\Rule\IsTagSubstringRule;
|
||||
use MyTube\Handling\Tag\Rule\TagAliasExistsRule;
|
||||
use MyTube\Handling\Tag\Rule\TagExistsRule;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
@ -22,6 +25,7 @@ return [
|
||||
/// Rule
|
||||
TagExistsRule::class => InjectionFactory::class,
|
||||
TagAliasExistsRule::class => InjectionFactory::class,
|
||||
IsTagSubstringRule::class => InjectionFactory::class,
|
||||
|
||||
/// Builder
|
||||
TagBuilder::class => AutoWiringFactory::class,
|
||||
@ -40,5 +44,8 @@ return [
|
||||
// Read Video List
|
||||
ReadVideoListQueryBuilder::class => AutoWiringFactory::class,
|
||||
ReadVideoListQueryHandler::class => InjectionFactory::class,
|
||||
// Read Thumbnail
|
||||
ReadThumbnailQueryBuilder::class => AutoWiringFactory::class,
|
||||
ReadThumbnailQueryHandler::class => InjectionFactory::class,
|
||||
],
|
||||
];
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Tag\Handler\Query\ReadThumbnail;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class ReadThumbnailQuery
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UuidInterface $tagUuid
|
||||
) {
|
||||
}
|
||||
|
||||
public function getTagUuid(): UuidInterface
|
||||
{
|
||||
return $this->tagUuid;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Tag\Handler\Query\ReadThumbnail;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
class ReadThumbnailQueryBuilder
|
||||
{
|
||||
public function build(
|
||||
UuidInterface $tagUuid
|
||||
): ReadThumbnailQuery {
|
||||
return new ReadThumbnailQuery(
|
||||
$tagUuid
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Tag\Handler\Query\ReadThumbnail;
|
||||
|
||||
use MyTube\Data\Business\Entity\Tag;
|
||||
use MyTube\Data\Business\Repository\TagRepository;
|
||||
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
|
||||
|
||||
class ReadThumbnailQueryHandler
|
||||
{
|
||||
/**
|
||||
* @InjectDoctrineRepository(
|
||||
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
|
||||
* entity="MyTube\Data\Business\Entity\Tag"
|
||||
* )
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly TagRepository $tagRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(ReadThumbnailQuery $readThumbnailQuery): ReadThumbnailQueryResult
|
||||
{
|
||||
$thumbnailVideo = null;
|
||||
|
||||
/** @var Tag $tag */
|
||||
$tag = $this->tagRepository->findOneBy([
|
||||
'id' => $readThumbnailQuery->getTagUuid()
|
||||
]);
|
||||
|
||||
$videoCount = $tag->getVideos()->count();
|
||||
|
||||
if ($videoCount > 0) {
|
||||
$thumbnailVideo = $tag->getVideos()[rand(0, $videoCount - 1)];
|
||||
}
|
||||
|
||||
return new ReadThumbnailQueryResult($thumbnailVideo);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyTube\Handling\Tag\Handler\Query\ReadThumbnail;
|
||||
|
||||
use MyTube\Data\Business\Entity\Video;
|
||||
|
||||
class ReadThumbnailQueryResult
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Video $thumbnailVideo
|
||||
) {
|
||||
}
|
||||
|
||||
public function getThumbnailVideo(): Video
|
||||
{
|
||||
return $this->thumbnailVideo;
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,6 @@ class ReadVideoListQueryHandler
|
||||
query: $readVideoListQuery->getQuery(),
|
||||
page: $readVideoListQuery->getPage(),
|
||||
perPage: $readVideoListQuery->getPerPage(),
|
||||
onlyTagless: false,
|
||||
tag: $tag
|
||||
)
|
||||
);
|
||||
|
||||
34
src/HandlingDomain/Tag/src/Rule/IsTagSubstringRule.php
Normal file
34
src/HandlingDomain/Tag/src/Rule/IsTagSubstringRule.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace MyTube\Handling\Tag\Rule;
|
||||
|
||||
use MyTube\Data\Business\Repository\TagRepository;
|
||||
use Reinfi\DependencyInjection\Annotation\InjectDoctrineRepository;
|
||||
|
||||
class IsTagSubstringRule
|
||||
{
|
||||
/**
|
||||
* @InjectDoctrineRepository(
|
||||
* entityManager="MyTube\Data\Business\Manager\MyTubeEntityManager",
|
||||
* entity="MyTube\Data\Business\Entity\Tag"
|
||||
* )
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly TagRepository $tagRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function appliesTo(
|
||||
string $substring,
|
||||
): bool
|
||||
{
|
||||
$substring = "%" . $substring . "%";
|
||||
|
||||
$qb = $this->tagRepository->createQueryBuilder('t')
|
||||
->where('t.description like :substring')
|
||||
->setParameter('substring', $substring);
|
||||
|
||||
|
||||
return count($qb->getQuery()->getResult()) !== 0;
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@ class VideoDurationAnalyzer
|
||||
{
|
||||
public function analyze(
|
||||
Video $video
|
||||
): void {
|
||||
): bool {
|
||||
if ($video->getDuration() === null) {
|
||||
$command = sprintf(
|
||||
"ffprobe -i %s%s -show_entries format=duration -v quiet -of csv='p=0'",
|
||||
@ -26,7 +26,9 @@ class VideoDurationAnalyzer
|
||||
$duration = shell_exec($command);
|
||||
if ($duration !== null) {
|
||||
$video->setDuration(intval($duration));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ class VideoTitleAnalyzer
|
||||
|
||||
$tags = $this->tagRepository->findAll();
|
||||
$matches = [];
|
||||
$appliedMatches = [];
|
||||
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
@ -50,10 +51,13 @@ class VideoTitleAnalyzer
|
||||
|
||||
/** @var Tag $match */
|
||||
foreach ($matches as $match) {
|
||||
$video->addTag($match);
|
||||
if(!$video->getTags()->contains($match)) {
|
||||
$appliedMatches[] = $match;
|
||||
$video->addTag($match);
|
||||
}
|
||||
}
|
||||
|
||||
return $matches;
|
||||
return $appliedMatches;
|
||||
}
|
||||
|
||||
private function normalizeString(string $string): string {
|
||||
|
||||
@ -9,8 +9,7 @@ class ReadListQuery
|
||||
public function __construct(
|
||||
private readonly ?string $query,
|
||||
private readonly int $page,
|
||||
private readonly int $perPage,
|
||||
private readonly bool $onlyTagless,
|
||||
private readonly int $perPage
|
||||
) {
|
||||
}
|
||||
|
||||
@ -28,9 +27,4 @@ class ReadListQuery
|
||||
{
|
||||
return $this->perPage;
|
||||
}
|
||||
|
||||
public function getOnlyTagless(): bool
|
||||
{
|
||||
return $this->onlyTagless;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,13 +10,11 @@ class ReadListQueryBuilder
|
||||
?string $query,
|
||||
int $page,
|
||||
int $perPage,
|
||||
bool $onlyTagless,
|
||||
): ReadListQuery {
|
||||
return new ReadListQuery(
|
||||
$query,
|
||||
$page,
|
||||
$perPage,
|
||||
$onlyTagless,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,8 +26,7 @@ class ReadListQueryHandler
|
||||
$this->videoRepository->findByFilter(
|
||||
query: $readListQuery->getQuery(),
|
||||
page: $readListQuery->getPage(),
|
||||
perPage: $readListQuery->getPerPage(),
|
||||
onlyTagless: $readListQuery->getOnlyTagless()
|
||||
perPage: $readListQuery->getPerPage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user