Commit fee2c1c0 authored by Yassine Doghri's avatar Yassine Doghri
Browse files

feat(pwa): add service-worker + webmanifest for each podcasts to have them install on devices

- configure service-worker using vite-plugin-pwa
- refactor Image entity to generate images of
different types based on size config
- add requirement for webp library for php gd to generate webp
images for instance
- add action to regenerate all instance images for eventual Images config
changes
- enhance google lighthouse metrics for pwa
parent 902f959b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ RUN apt-get update \
    # https://github.com/mlocati/docker-php-extension-installer (included in php's docker image)
    libicu-dev \
    libpng-dev \
    libwebp-dev \
    libjpeg-dev \
    zlib1g-dev \
    libzip-dev \
@@ -44,7 +45,7 @@ RUN apt-get update \
    && docker-php-ext-install intl  \
    && docker-php-ext-install zip \
    # gd for image processing
    && docker-php-ext-configure gd --with-jpeg \
    && docker-php-ext-configure gd --with-webp --with-jpeg \
    && docker-php-ext-install gd \
    # redis extension for cache
    && pecl install -o -f redis \
+2 −1
Original line number Diff line number Diff line
@@ -69,7 +69,8 @@ PHP version 8.0 or higher is required, with the following extensions installed:
- [intl](https://php.net/manual/en/intl.requirements.php)
- [libcurl](https://php.net/manual/en/curl.requirements.php)
- [mbstring](https://php.net/manual/en/mbstring.installation.php)
- [gd](https://www.php.net/manual/en/image.installation.php)
- [gd](https://www.php.net/manual/en/image.installation.php) with **JPEG**,
  **PNG** and **WEBP** libraries.

Additionally, make sure that the following extensions are enabled in your PHP:

+86 −17
Original line number Diff line number Diff line
@@ -47,15 +47,57 @@ class Images extends BaseConfig
     *
     * Array values are as follows: 'name' => [width, height]
     *
     * @var array<string, int[]>
     * @var array<string, array<string, int|string>>
     */
    public array $podcastCoverSizes = [
        'tiny' => [40, 40],
        'thumbnail' => [150, 150],
        'medium' => [320, 320],
        'large' => [1024, 1024],
        'feed' => [1400, 1400],
        'id3' => [500, 500],
        'tiny' => [
            'width' => 40,
            'height' => 40,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'thumbnail' => [
            'width' => 150,
            'height' => 150,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'medium' => [
            'width' => 320,
            'height' => 320,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'large' => [
            'width' => 1024,
            'height' => 1024,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'feed' => [
            'width' => 1400,
            'height' => 1400,
        ],
        'id3' => [
            'width' => 500,
            'height' => 500,
        ],
        'federation' => [
            'width' => 400,
            'height' => 400,
        ],
        'webmanifest192' => [
            'width' => 192,
            'height' => 192,
            'mimetype' => 'image/png',
            'extension' => 'png',
        ],
        'webmanifest512' => [
            'width' => 512,
            'height' => 512,
            'mimetype' => 'image/png',
            'extension' => 'png',
        ],
    ];

    /**
@@ -63,14 +105,25 @@ class Images extends BaseConfig
     *
     * Uploaded podcast header covers are of 3:1 ratio
     *
     * Array values are as follows: 'name' => [width, height]
     *
     * @var array<string, int[]>
     * @var array<string, array<string, int|string>>
     */
    public array $podcastBannerSizes = [
        'small' => [320, 128],
        'medium' => [960, 320],
        'large' => [1500, 500],
        'small' => [
            'width' => 320,
            'height' => 128,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'medium' => [
            'width' => 960,
            'height' => 320,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'federation' => [
            'width' => 1500,
            'height' => 500,
        ],
    ];

    public string $podcastBannerDefaultPath = 'castopod-banner-default.jpg';
@@ -84,11 +137,27 @@ class Images extends BaseConfig
     *
     * Array values are as follows: 'name' => [width, height]
     *
     * @var array<string, int[]>
     * @var array<string, array<string, int|string>>
     */
    public array $personAvatarSizes = [
        'tiny' => [40, 40],
        'thumbnail' => [150, 150],
        'medium' => [320, 320],
        'tiny' => [
            'width' => 40,
            'height' => 40,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'thumbnail' => [
            'width' => 150,
            'height' => 150,
            'mimetype' => 'image/webp',
            'extension' => 'webp',
        ],
        'medium' => [
            'width' => 320,
            'height' => 320,
            'mimetype' =>
             'image/webp',
            'extension' => 'webp',
        ],
    ];
}
+4 −0
Original line number Diff line number Diff line
@@ -65,6 +65,10 @@ $routes->group('@(:podcastHandle)', function ($routes): void {
    $routes->get('/', 'PodcastController::activity/$1', [
        'as' => 'podcast-activity',
    ]);
    $routes->get('manifest.webmanifest', 'WebmanifestController::podcastManifest/$1', [
        'as' => 'podcast-webmanifest',
    ]);

    // override default Fediverse Library's actor route
    $routes->options('/', 'ActivityPubController::preflight');
    $routes->get('/', 'PodcastController::activity/$1', [
+4 −4
Original line number Diff line number Diff line
@@ -204,9 +204,9 @@ class EpisodeController extends BaseController
            'height' => 144,
            'thumbnail_url' => $this->episode->cover->large_url,
            'thumbnail_width' => config('Images')
                ->podcastCoverSizes['large'][0],
                ->podcastCoverSizes['large']['width'],
            'thumbnail_height' => config('Images')
                ->podcastCoverSizes['large'][1],
                ->podcastCoverSizes['large']['height'],
        ]);
    }

@@ -222,8 +222,8 @@ class EpisodeController extends BaseController
        $oembed->addChild('author_name', $this->podcast->title);
        $oembed->addChild('author_url', $this->podcast->link);
        $oembed->addChild('thumbnail', $this->episode->cover->large_url);
        $oembed->addChild('thumbnail_width', (string) config('Images')->podcastCoverSizes['large'][0]);
        $oembed->addChild('thumbnail_height', (string) config('Images')->podcastCoverSizes['large'][1]);
        $oembed->addChild('thumbnail_width', (string) config('Images')->podcastCoverSizes['large']['width']);
        $oembed->addChild('thumbnail_height', (string) config('Images')->podcastCoverSizes['large']['height']);
        $oembed->addChild(
            'html',
            htmlentities(
Loading