diff --git a/FAQ.md b/FAQ.md index fd20a18a..ece86b14 100644 --- a/FAQ.md +++ b/FAQ.md @@ -351,9 +351,11 @@ $ mv /config/db/watchstate_v01-repaired.db /config/db/watchstate_v01.db * tvrage://(id) * anidb://(id) * ytinforeader://( - id) [jellyfin](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin) & [Emby](https://github.com/arabcoders/emby-ytdlp-info-reader-plugin). `(A yt-dlp info reader plugin)`. + id) [jellyfin](https://github.com/arabcoders/jf-ytdlp-info-reader-plugin) & [Emby](https://github.com/arabcoders/emby-ytdlp-info-reader-plugin). + `(A yt-dlp info reader plugin)`. * cmdb://( - id) [jellyfin](https://github.com/arabcoders/jf-custom-metadata-db) & [Emby](https://github.com/arabcoders/emby-custom-metadata-db). `(User custom metadata database)`. + id) [jellyfin](https://github.com/arabcoders/jf-custom-metadata-db) & [Emby](https://github.com/arabcoders/emby-custom-metadata-db). + `(User custom metadata database)`. --- @@ -739,7 +741,9 @@ If everything is working correctly you should see something like this previous j ---- -### I keep receiving this warning in log `INFO: Ignoring [xxx] Episode range, and treating it as single episode. Backend says it covers [00-00]`? +### I keep receiving this warning in log + +`INFO: Ignoring [xxx] Episode range, and treating it as single episode. Backend says it covers [00-00]`? We recently added guard clause to prevent backends from sending possibly invalid episode ranges, as such if you see this, @@ -881,16 +885,53 @@ The feature first scan your entire history for reported media file paths. Depend Lets says you have a media file `/media/series/season 1/episode 1.mkv` The scanner does the following: -* `/media` Does this path component exists? if not mark everything starting from `/media` as not found. if it exists simply move to the next component until we reach the end of the path. +* `/media` Does this path component exists? if not mark everything starting from `/media` as not found. if it exists + simply move to the next component until we reach the end of the path. * `/media/series` Do same as above. * `/media/series/season 1` Do same as above. * `/media/series/season 1/episode 1.mkv` Do same as above. -Using this approach allow us to cache calls and reduce unnecessary calls to the filesystem. If you have for example `/media/seriesX/` with thousands of files, -and the path component `/media/seriesX` doesn't exists, we simply ignore everything that starts with `/media/seriesX/` and treat them as not found. +Using this approach allow us to cache calls and reduce unnecessary calls to the filesystem. If you have for example +`/media/seriesX/` with thousands of files, +and the path component `/media/seriesX` doesn't exists, we simply ignore everything that starts with `/media/seriesX/` +and treat them as not found. This helps with slow stat calls in network shares, or cloud storage. -Everytime we do a stat call we cache it for 1 hour, so if we have multiple records reporting the same path, we only do the stat check once. +Everytime we do a stat call we cache it for 1 hour, so if we have multiple records reporting the same path, we only do +the stat check once. --- + +### How to use hardware acceleration for video transcoding in the WebUI? + +As the container is rootless, we cannot do the necessary changes to the container to enable hardware acceleration. +However, We do have the drivers and ffmpeg already installed and the CPU transcoding should work regardless. To enable +hardware acceleration You need to alter your `compose.yaml` file to mount the necessary devices to the container. Here +is an example of how to do it for debian based systems. + +```yaml +services: + watchstate: + image: ghcr.io/arabcoders/watchstate:latest + # To change the user/group id associated with the tool change the following line. + user: "${UID:-1000}:${GID:-1000}" + group_add: + - "44" # Add video group to the container. + - "110" # Add render group to the container. + container_name: watchstate + restart: unless-stopped + ports: + - "8080:8080" # The port which will serve WebUI + API + Webhooks + volumes: + - ./data:/config:rw # mount current directory to container /config directory. + - /dev/dri:/dev/dri # mount the dri devices to the container. + - /storage/media:/media:ro # mount your media directory to the container. +``` + +This setup should work for VAAPI encoding in `x86_64` containers, for other architectures you need to adjust the +`/dev/dri` to match your hardware. There are currently an issue with nvidia h264_nvenc encoding, the alpine build for +`ffmpeg`doesn't include the codec. + +Note: the tip about adding the group_add came from the user `binarypancakes` in discord. + diff --git a/composer.json b/composer.json index 2f7cf393..e2330a0f 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,9 @@ "dragonmantank/cron-expression": "^3.3.2", "halaxa/json-machine": "^1.1.1", "league/route": "^5.1.2", - "psy/psysh": "^0.11.22" + "psy/psysh": "^0.11.22", + "symfony/event-dispatcher": "^6.1.4", + "ramsey/uuid": "^4.5.1" }, "suggest": { "ext-sockets": "For UDP commincations." diff --git a/composer.lock b/composer.lock index 6f11c23b..923ded1a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,68 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e386d8f65a092fddeb914449ac6231a0", + "content-hash": "1c1f4ebab4be7bb510216bdcaec0175f", "packages": [ + { + "name": "brick/math", + "version": "0.12.1", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "f510c0a40911935b77b86859eb5223d58d660df1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1", + "reference": "f510c0a40911935b77b86859eb5223d58d660df1", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^10.1", + "vimeo/psalm": "5.16.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "bignumber", + "brick", + "decimal", + "integer", + "math", + "mathematics", + "rational" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.12.1" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2023-11-29T23:19:16+00:00" + }, { "name": "dragonmantank/cron-expression", "version": "v3.3.3", @@ -815,6 +875,56 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, { "name": "psr/http-client", "version": "1.0.3", @@ -1269,6 +1379,187 @@ }, "time": "2023-10-14T21:56:36+00:00" }, + { + "name": "ramsey/collection", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.28.3", + "fakerphp/faker": "^1.21", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^1.0", + "mockery/mockery": "^1.5", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpcsstandards/phpcsutils": "^1.0.0-rc1", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18.4", + "ramsey/coding-standard": "^2.0.3", + "ramsey/conventional-commits": "^1.3", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], + "time": "2022-12-31T21:50:55+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.7.6", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", + "ext-json": "*", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.7.6" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2024-04-27T21:32:50+00:00" + }, { "name": "symfony/cache", "version": "v6.4.10", @@ -1602,6 +1893,162 @@ ], "time": "2024-04-18T09:32:20+00:00" }, + { + "name": "symfony/event-dispatcher", + "version": "v6.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b", + "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "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": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8" + }, + "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": "2024-05-31T14:49:08+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.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": "2024-04-18T09:32:20+00:00" + }, { "name": "symfony/http-client", "version": "v6.4.10", @@ -3114,12 +3561,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "fe2777b484817ebbbe50ad685af7525560198c59" + "reference": "251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/fe2777b484817ebbbe50ad685af7525560198c59", - "reference": "fe2777b484817ebbbe50ad685af7525560198c59", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e", + "reference": "251a4f1fefcc6e6cc90d50514fee6b6e3745cb3e", "shasum": "" }, "conflict": { @@ -3285,7 +3732,7 @@ "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev", + "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev|>=3.3,<3.3.40", "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", "ezsystems/ezplatform-user": ">=1,<1.0.1", "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31", @@ -3366,6 +3813,7 @@ "hyn/multi-tenant": ">=5.6,<5.7.2", "ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6.0.0-beta1,<4.6.9", "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", + "ibexa/fieldtype-richtext": ">=4.6,<4.6.10", "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", "ibexa/post-install": "<=1.0.4", "ibexa/solr": ">=4.5,<4.5.4", @@ -3608,6 +4056,7 @@ "pubnub/pubnub": "<6.1", "pusher/pusher-php-server": "<2.2.1", "pwweb/laravel-core": "<=0.3.6.0-beta", + "pxlrbt/filament-excel": "<2.3.3", "pyrocms/pyrocms": "<=3.9.1", "qcubed/qcubed": "<=3.1.1", "quickapps/cms": "<=2.0.0.0-beta2", @@ -3921,7 +4370,7 @@ "type": "tidelift" } ], - "time": "2024-08-08T21:04:55+00:00" + "time": "2024-08-14T19:05:08+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/config.php b/config/config.php index b7de6b7e..5ed97dab 100644 --- a/config/config.php +++ b/config/config.php @@ -5,6 +5,7 @@ declare(strict_types=1); use App\Backends\Emby\EmbyClient; use App\Backends\Jellyfin\JellyfinClient; use App\Backends\Plex\PlexClient; +use App\Commands\Events\DispatchCommand; use App\Commands\State\BackupCommand; use App\Commands\State\ExportCommand; use App\Commands\State\ImportCommand; @@ -312,6 +313,31 @@ return (function () { 'timer' => $checkTaskTimer((string)env('WS_CRON_REQUESTS_AT', '*/2 * * * *'), '*/2 * * * *'), 'args' => env('WS_CRON_REQUESTS_ARGS', '-v --no-stats'), ], + DispatchCommand::TASK_NAME => [ + 'command' => DispatchCommand::ROUTE, + 'name' => DispatchCommand::TASK_NAME, + 'info' => 'Dispatch queued events to their respective listeners.', + 'enabled' => true, + 'timer' => '* * * * *', + 'args' => '-v', + ], + ], + ]; + + $config['events'] = [ + 'logfile' => ag($config, 'tmpDir') . '/logs/events.' . $logDateFormat . '.log', + 'listeners' => [ + 'cache' => new DateInterval(env('WS_EVENTS_LISTENERS_CACHE', 'PT1M')), + 'file' => env('APP_EVENTS_FILE', function () use ($config): string|null { + $file = ag($config, 'path') . '/config/events.php'; + return file_exists($file) ? $file : null; + }), + 'locations' => [ + __DIR__ . '/../src/API/', + __DIR__ . '/../src/Backends/', + __DIR__ . '/../src/Commands/', + __DIR__ . '/../src/Listeners/', + ] ], ]; diff --git a/config/services.php b/config/services.php index 46281601..7db05c73 100644 --- a/config/services.php +++ b/config/services.php @@ -5,6 +5,7 @@ declare(strict_types=1); use App\Libs\Config; use App\Libs\Container; use App\Libs\Database\DatabaseInterface as iDB; +use App\Libs\Database\DBLayer; use App\Libs\Database\PDO\PDOAdapter; use App\Libs\Entity\StateEntity; use App\Libs\Entity\StateInterface; @@ -19,6 +20,7 @@ use App\Libs\Mappers\ImportInterface as iImport; use App\Libs\QueueRequests; use App\Libs\Uri; use Monolog\Logger; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface as iLogger; use Psr\SimpleCache\CacheInterface; @@ -29,6 +31,7 @@ use Symfony\Component\Cache\Psr16Cache; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpClient\CurlHttpClient; use Symfony\Component\Yaml\Yaml; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -217,6 +220,13 @@ return (function (): array { ], ], + DBLayer::class => [ + 'class' => fn(PDO $pdo): DBLayer => new DBLayer($pdo), + 'args' => [ + PDO::class, + ], + ], + MemoryMapper::class => [ 'class' => function (iLogger $logger, iDB $db, CacheInterface $cache): iImport { return (new MemoryMapper(logger: $logger, db: $db, cache: $cache)) @@ -249,5 +259,10 @@ return (function (): array { MemoryMapper::class ], ], + + EventDispatcherInterface::class => [ + 'class' => fn(): EventDispatcher => new EventDispatcher(), + ], + ]; })(); diff --git a/frontend/components/Markdown.vue b/frontend/components/Markdown.vue index 4fb0f941..4d0bf6a6 100644 --- a/frontend/components/Markdown.vue +++ b/frontend/components/Markdown.vue @@ -17,7 +17,10 @@ const props = defineProps({ const content = ref('') const api_url = useStorage('api_url', '') -onMounted(() => fetch(`${api_url.value}${props.file}`).then(response => response.text()).then(text => { +onMounted(async () => { + const response = await fetch(`${api_url.value}${props.file}?_=${Date.now()}`) + const text = await response.text() + marked.use({ gfm: true, renderer: { @@ -43,7 +46,8 @@ onMounted(() => fetch(`${api_url.value}${props.file}`).then(response => response }, ...baseUrl(api_url.value), }); + content.value = marked.parse(text) -})); +}); diff --git a/frontend/pages/tasks.vue b/frontend/pages/tasks.vue index e0337302..2f79e54d 100644 --- a/frontend/pages/tasks.vue +++ b/frontend/pages/tasks.vue @@ -50,7 +50,7 @@