Compare commits
5 Commits
v0.29.4
...
dev-notifi
| Author | SHA1 | Date | |
|---|---|---|---|
| 575fc08f24 | |||
| 87bdde801d | |||
| 7d35b6266b | |||
| caeda625fd | |||
| d710e31d2b |
7
.env
7
.env
@@ -51,3 +51,10 @@ OIDC_CLIENT_ID="Enter your OIDC client id"
|
|||||||
OIDC_CLIENT_SECRET="Enter your OIDC client secret"
|
OIDC_CLIENT_SECRET="Enter your OIDC client secret"
|
||||||
OIDC_BYPASS_FORM_LOGIN=false
|
OIDC_BYPASS_FORM_LOGIN=false
|
||||||
###< drenso/symfony-oidc-bundle ###
|
###< drenso/symfony-oidc-bundle ###
|
||||||
|
|
||||||
|
###> symfony/ntfy-notifier ###
|
||||||
|
# NTFY_DSN=ntfy://default/TOPIC
|
||||||
|
###< symfony/ntfy-notifier ###
|
||||||
|
|
||||||
|
NOTIFICATION_TRANSPORT=
|
||||||
|
NTFY_DNS=
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
"symfony/mailer": "7.3.*",
|
"symfony/mailer": "7.3.*",
|
||||||
"symfony/mercure-bundle": "^0.3.9",
|
"symfony/mercure-bundle": "^0.3.9",
|
||||||
"symfony/messenger": "7.3.*",
|
"symfony/messenger": "7.3.*",
|
||||||
|
"symfony/notifier": "7.3.*",
|
||||||
|
"symfony/ntfy-notifier": "7.3.*",
|
||||||
"symfony/runtime": "7.3.*",
|
"symfony/runtime": "7.3.*",
|
||||||
"symfony/scheduler": "7.3.*",
|
"symfony/scheduler": "7.3.*",
|
||||||
"symfony/security-bundle": "7.3.*",
|
"symfony/security-bundle": "7.3.*",
|
||||||
|
|||||||
148
composer.lock
generated
148
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": "f4953f7b233a466d94269f35096f3385",
|
"content-hash": "6f57ba35ae317ec6370836bda0012db8",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "1tomany/rich-bundle",
|
"name": "1tomany/rich-bundle",
|
||||||
@@ -7578,6 +7578,152 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-02-19T08:51:26+00:00"
|
"time": "2025-02-19T08:51:26+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/notifier",
|
||||||
|
"version": "v7.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/notifier.git",
|
||||||
|
"reference": "9e68a3266c8b0381f8756022b1c1ba3c0264416e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/notifier/zipball/9e68a3266c8b0381f8756022b1c1ba3c0264416e",
|
||||||
|
"reference": "9e68a3266c8b0381f8756022b1c1ba3c0264416e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"psr/log": "^1|^2|^3"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/event-dispatcher": "<6.4",
|
||||||
|
"symfony/event-dispatcher-contracts": "<2.5",
|
||||||
|
"symfony/http-client-contracts": "<2.5",
|
||||||
|
"symfony/http-kernel": "<6.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/event-dispatcher-contracts": "^2.5|^3",
|
||||||
|
"symfony/http-client-contracts": "^2.5|^3",
|
||||||
|
"symfony/http-foundation": "^6.4|^7.0",
|
||||||
|
"symfony/messenger": "^6.4|^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Notifier\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Sends notifications via one or more channels (email, SMS, ...)",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"notification",
|
||||||
|
"notifier"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/notifier/tree/v7.3.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-05-01T12:12:53+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/ntfy-notifier",
|
||||||
|
"version": "v7.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/ntfy-notifier.git",
|
||||||
|
"reference": "094154ba36eac54078a71076effe46feaec59036"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/ntfy-notifier/zipball/094154ba36eac54078a71076effe46feaec59036",
|
||||||
|
"reference": "094154ba36eac54078a71076effe46feaec59036",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"symfony/clock": "^6.4|^7.0",
|
||||||
|
"symfony/http-client": "^6.4|^7.0",
|
||||||
|
"symfony/notifier": "^7.3"
|
||||||
|
},
|
||||||
|
"type": "symfony-notifier-bridge",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Notifier\\Bridge\\Ntfy\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mickael Perraud",
|
||||||
|
"email": "mikaelkael.fr@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony Ntfy Notifier Bridge",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"Ntfy",
|
||||||
|
"notifier"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/ntfy-notifier/tree/v7.3.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-02-13T10:27:54+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/options-resolver",
|
"name": "symfony/options-resolver",
|
||||||
"version": "v7.3.0",
|
"version": "v7.3.0",
|
||||||
|
|||||||
13
config/packages/notifier.yaml
Normal file
13
config/packages/notifier.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
framework:
|
||||||
|
notifier:
|
||||||
|
chatter_transports:
|
||||||
|
texter_transports:
|
||||||
|
ntfy: '%notification.ntfy.dsn%'
|
||||||
|
channel_policy:
|
||||||
|
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
|
||||||
|
urgent: ['email']
|
||||||
|
high: ['email']
|
||||||
|
medium: ['email']
|
||||||
|
low: ['email']
|
||||||
|
admin_recipients:
|
||||||
|
- { email: admin@example.com }
|
||||||
@@ -44,6 +44,10 @@ parameters:
|
|||||||
auth.oidc.client_secret: '%env(OIDC_CLIENT_SECRET)%'
|
auth.oidc.client_secret: '%env(OIDC_CLIENT_SECRET)%'
|
||||||
auth.oidc.bypass_form_login: '%env(bool:OIDC_BYPASS_FORM_LOGIN)%'
|
auth.oidc.bypass_form_login: '%env(bool:OIDC_BYPASS_FORM_LOGIN)%'
|
||||||
|
|
||||||
|
# Notifications
|
||||||
|
notification.transport: '%env(NOTIFICATION_TRANSPORT)%'
|
||||||
|
notification.ntfy.dsn: '%env(NTFY_DSN)%'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# default configuration for services in *this* file
|
# default configuration for services in *this* file
|
||||||
_defaults:
|
_defaults:
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||||
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||||
tty: true
|
|
||||||
deploy:
|
deploy:
|
||||||
replicas: 2
|
replicas: 2
|
||||||
volumes:
|
volumes:
|
||||||
@@ -16,6 +15,10 @@ services:
|
|||||||
- mercure_config:/config
|
- mercure_config:/config
|
||||||
depends_on:
|
depends_on:
|
||||||
- database
|
- database
|
||||||
|
logging:
|
||||||
|
driver: "gelf"
|
||||||
|
options:
|
||||||
|
gelf-address: "tcp://192.168.1.197:12202"
|
||||||
|
|
||||||
|
|
||||||
worker:
|
worker:
|
||||||
@@ -29,6 +32,10 @@ services:
|
|||||||
replicas: 2
|
replicas: 2
|
||||||
depends_on:
|
depends_on:
|
||||||
- app
|
- app
|
||||||
|
logging:
|
||||||
|
driver: "gelf"
|
||||||
|
options:
|
||||||
|
gelf-address: "tcp://192.168.1.197:12203"
|
||||||
|
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
@@ -40,6 +47,11 @@ services:
|
|||||||
command: -vv
|
command: -vv
|
||||||
depends_on:
|
depends_on:
|
||||||
- app
|
- app
|
||||||
|
logging:
|
||||||
|
driver: "gelf"
|
||||||
|
options:
|
||||||
|
gelf-address: "tcp://192.168.1.197:12204"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ final class ConfigResolver
|
|||||||
|
|
||||||
#[Autowire(param: 'auth.oidc.bypass_form_login')]
|
#[Autowire(param: 'auth.oidc.bypass_form_login')]
|
||||||
private ?bool $authOidcBypassFormLogin = null,
|
private ?bool $authOidcBypassFormLogin = null,
|
||||||
|
|
||||||
|
#[Autowire(param: 'notification.transport')]
|
||||||
|
private ?string $notificationTransport = null,
|
||||||
|
|
||||||
|
#[Autowire(param: 'notification.ntfy.dsn')]
|
||||||
|
private ?string $notificationNtfyDsn = null,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function validate(): bool
|
public function validate(): bool
|
||||||
@@ -54,6 +60,12 @@ final class ConfigResolver
|
|||||||
$valid = false;
|
$valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $this->notificationTransport) {
|
||||||
|
if (null === $this->notificationNtfyDsn || "" === $this->notificationNtfyDsn) {
|
||||||
|
$this->messages[] = "Your NOTIFICATION_TRANSPORT is set to 'ntfy' but you don't have the NTFY_DSN environment variable set.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $valid;
|
return $valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,33 +2,53 @@
|
|||||||
|
|
||||||
namespace App\Base\Service;
|
namespace App\Base\Service;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\Mercure\HubInterface;
|
use Symfony\Component\Mercure\HubInterface;
|
||||||
use Symfony\Component\Mercure\Update;
|
use Symfony\Component\Mercure\Update;
|
||||||
|
use Symfony\Component\Notifier\Notification\Notification;
|
||||||
|
use Symfony\Component\Notifier\NotifierInterface;
|
||||||
use Twig\Environment;
|
use Twig\Environment;
|
||||||
|
|
||||||
readonly class Broadcaster
|
readonly class Broadcaster
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
#[Autowire(param: 'notification.transport')]
|
||||||
|
private string $notificationTransport,
|
||||||
#[Autowire(service: 'twig')]
|
#[Autowire(service: 'twig')]
|
||||||
private Environment $renderer,
|
private Environment $renderer,
|
||||||
private HubInterface $hub,
|
private HubInterface $hub,
|
||||||
private RequestStack $requestStack,
|
private RequestStack $requestStack,
|
||||||
|
private NotifierInterface $notifier,
|
||||||
|
private LoggerInterface $logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function alert(string $title, string $message, string $type = "success"): void
|
public function alert(string $title, string $message, string $type = "success", bool $sendPush = false): void
|
||||||
{
|
{
|
||||||
$userAlertTopic = $this->requestStack->getCurrentRequest()->getSession()->get('mercure_alert_topic');
|
try {
|
||||||
$update = new Update(
|
$userAlertTopic = $this->requestStack->getCurrentRequest()->getSession()->get('mercure_alert_topic');
|
||||||
$userAlertTopic,
|
$update = new Update(
|
||||||
$this->renderer->render('broadcast/Alert.stream.html.twig', [
|
$userAlertTopic,
|
||||||
'alert_id' => uniqid(),
|
$this->renderer->render('broadcast/Alert.stream.html.twig', [
|
||||||
'title' => $title,
|
'alert_id' => uniqid(),
|
||||||
'message' => $message,
|
'title' => $title,
|
||||||
'type' => $type,
|
'message' => $message,
|
||||||
])
|
'type' => $type,
|
||||||
);
|
])
|
||||||
$this->hub->publish($update);
|
);
|
||||||
|
$this->hub->publish($update);
|
||||||
|
} catch (\Throwable $exception) {
|
||||||
|
// ToDo: look for better handling to get message to end user
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === $sendPush && in_array($this->notificationTransport, ['ntfy'])) {
|
||||||
|
try {
|
||||||
|
$notification = new Notification($title, ['push'])->content($message);
|
||||||
|
$this->notifier->send($notification);
|
||||||
|
} catch (\Throwable $exception) {
|
||||||
|
$this->logger->error('Unable to send push notification: ' . $exception->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Download\Downloader;
|
namespace App\Download\Downloader;
|
||||||
|
|
||||||
|
use App\Base\Service\Broadcaster;
|
||||||
use App\Base\Service\MediaFiles;
|
use App\Base\Service\MediaFiles;
|
||||||
use App\Download\Framework\Entity\Download;
|
use App\Download\Framework\Entity\Download;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
@@ -19,6 +20,7 @@ class ProcessDownloader implements DownloaderInterface
|
|||||||
private EntityManagerInterface $entityManager,
|
private EntityManagerInterface $entityManager,
|
||||||
private MediaFiles $mediaFiles,
|
private MediaFiles $mediaFiles,
|
||||||
private CacheInterface $cache,
|
private CacheInterface $cache,
|
||||||
|
private readonly Broadcaster $broadcaster,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,6 +84,7 @@ class ProcessDownloader implements DownloaderInterface
|
|||||||
});
|
});
|
||||||
if ($downloadEntity->getStatus() !== 'Paused') {
|
if ($downloadEntity->getStatus() !== 'Paused') {
|
||||||
$downloadEntity->setProgress(100);
|
$downloadEntity->setProgress(100);
|
||||||
|
$this->alertComplete($downloadEntity);
|
||||||
}
|
}
|
||||||
} catch (ProcessFailedException $exception) {
|
} catch (ProcessFailedException $exception) {
|
||||||
$downloadEntity->setStatus('Failed');
|
$downloadEntity->setStatus('Failed');
|
||||||
@@ -105,4 +108,15 @@ class ProcessDownloader implements DownloaderInterface
|
|||||||
|
|
||||||
throw new \Exception("There is no download path for media type: $mediaType");
|
throw new \Exception("There is no download path for media type: $mediaType");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function alertComplete(Download $download): void
|
||||||
|
{
|
||||||
|
if ("tvshows" === $download->getMediaType()) {
|
||||||
|
$message = '"' . $download->getTitle() . '" - ' . $download->getEpisodeId() . ' has finished downloading.';
|
||||||
|
} else {
|
||||||
|
$message = '"' . $download->getTitle() . '" has finished downloading.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->broadcaster->alert('Success', $message, sendPush: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
21
symfony.lock
21
symfony.lock
@@ -232,6 +232,27 @@
|
|||||||
"config/packages/messenger.yaml"
|
"config/packages/messenger.yaml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/notifier": {
|
||||||
|
"version": "7.3",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "5.0",
|
||||||
|
"ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/notifier.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symfony/ntfy-notifier": {
|
||||||
|
"version": "7.3",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "6.4",
|
||||||
|
"ref": "0d5e496659d7361bb4e6648eb8332f8cf097533d"
|
||||||
|
}
|
||||||
|
},
|
||||||
"symfony/property-info": {
|
"symfony/property-info": {
|
||||||
"version": "7.3",
|
"version": "7.3",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
@@ -55,7 +55,11 @@
|
|||||||
|
|
||||||
<turbo-stream action="prepend" target="alert_list">
|
<turbo-stream action="prepend" target="alert_list">
|
||||||
<template>
|
<template>
|
||||||
<twig:Alert title="Finished downloading" message="{{ entity.title }}" alert_id="{{ entity.id }}" data-controller="alert" />
|
{% if entity.mediaType == "tvshows" %}
|
||||||
|
<twig:Alert title="Success" message="{{ entity.title }} - ({{ entity.episodeId }}) has finished downloading." alert_id="{{ entity.id }}" data-controller="alert" />
|
||||||
|
{% else %}
|
||||||
|
<twig:Alert title="Success" message="{{ entity.title }} has finished downloading." alert_id="{{ entity.id }}" data-controller="alert" />
|
||||||
|
{% endif %}
|
||||||
</template>
|
</template>
|
||||||
</turbo-stream>
|
</turbo-stream>
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr id="active_monitors_no_monitors">
|
<tr id="active_monitors_no_monitors">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-xs uppercase text-center col-span-2 font-medium" colspan="100%">
|
<td class="px-6 py-4 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-900 text-center text-xs uppercase font-medium" colspan="100%">
|
||||||
No monitors
|
No monitors
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user