feat: add housekeeping task to run after migrations
add run housekeeping button in general settings page
This commit is contained in:
parent
38899124ec
commit
89dee41d58
|
@ -145,6 +145,21 @@ class MediaModel extends Model
|
||||||
return $this->update($media->id, $media);
|
return $this->update($media->id, $media);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<mixed>
|
||||||
|
*/
|
||||||
|
public function getAllOfType(): array
|
||||||
|
{
|
||||||
|
$result = $this->where('type', $this->fileType)
|
||||||
|
->findAll();
|
||||||
|
$mediaClass = $this->returnType;
|
||||||
|
foreach ($result as $key => $media) {
|
||||||
|
$result[$key] = new $mediaClass($media->toArray(false, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public function deleteMedia(object $media): bool
|
public function deleteMedia(object $media): bool
|
||||||
{
|
{
|
||||||
$media->deleteFile();
|
$media->deleteFile();
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
<g>
|
||||||
|
<path fill="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M20 20a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-9H1l10.327-9.388a1 1 0 0 1 1.346 0L23 11h-3v9zM8.592 13.808l-.991.572 1 1.733.993-.573a3.5 3.5 0 0 0 1.405.811v1.145h2.002V16.35a3.5 3.5 0 0 0 1.405-.81l.992.572L16.4 14.38l-.991-.572a3.504 3.504 0 0 0 0-1.62l.991-.573-1-1.733-.993.573A3.5 3.5 0 0 0 13 9.645V8.5h-2.002v1.144a3.5 3.5 0 0 0-1.405.811l-.992-.573L7.6 11.616l.991.572a3.504 3.504 0 0 0 0 1.62zm3.408.69a1.5 1.5 0 1 1-.002-3.001 1.5 1.5 0 0 1 .002 3z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 602 B |
|
@ -46,6 +46,12 @@ class Button extends Component
|
||||||
'large' => 'text-base leading-6',
|
'large' => 'text-base leading-6',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$iconSize = [
|
||||||
|
'small' => 'text-sm',
|
||||||
|
'base' => 'text-lg',
|
||||||
|
'large' => 'text-2xl',
|
||||||
|
];
|
||||||
|
|
||||||
$basePaddings = [
|
$basePaddings = [
|
||||||
'small' => 'px-3 py-1',
|
'small' => 'px-3 py-1',
|
||||||
'base' => 'px-3 py-2',
|
'base' => 'px-3 py-2',
|
||||||
|
@ -77,14 +83,14 @@ class Button extends Component
|
||||||
if ($this->iconLeft !== '') {
|
if ($this->iconLeft !== '') {
|
||||||
$this->slot = (new Icon([
|
$this->slot = (new Icon([
|
||||||
'glyph' => $this->iconLeft,
|
'glyph' => $this->iconLeft,
|
||||||
'class' => 'mr-2 opacity-75',
|
'class' => 'mr-2 opacity-75' . ' ' . $iconSize[$this->size],
|
||||||
]))->render() . $this->slot;
|
]))->render() . $this->slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->iconRight !== '') {
|
if ($this->iconRight !== '') {
|
||||||
$this->slot .= (new Icon([
|
$this->slot .= (new Icon([
|
||||||
'glyph' => $this->iconRight,
|
'glyph' => $this->iconRight,
|
||||||
'class' => 'ml-2 opacity-75',
|
'class' => 'ml-2 opacity-75' . ' ' . $iconSize[$this->size],
|
||||||
]))->render();
|
]))->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,10 @@ $routes->group(
|
||||||
'as' => 'settings-images-regenerate',
|
'as' => 'settings-images-regenerate',
|
||||||
'filter' => 'permission:settings-manage',
|
'filter' => 'permission:settings-manage',
|
||||||
]);
|
]);
|
||||||
|
$routes->post('instance-housekeeping-run', 'SettingsController::runHousekeeping', [
|
||||||
|
'as' => 'settings-housekeeping-run',
|
||||||
|
'filter' => 'permission:settings-manage',
|
||||||
|
]);
|
||||||
$routes->get('theme', 'SettingsController::theme', [
|
$routes->get('theme', 'SettingsController::theme', [
|
||||||
'as' => 'settings-theme',
|
'as' => 'settings-theme',
|
||||||
'filter' => 'permission:settings-manage',
|
'filter' => 'permission:settings-manage',
|
||||||
|
|
|
@ -10,8 +10,12 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Modules\Admin\Controllers;
|
namespace Modules\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Entities\Media\Image;
|
||||||
|
use App\Models\ActorModel;
|
||||||
|
use App\Models\MediaModel;
|
||||||
use App\Models\PersonModel;
|
use App\Models\PersonModel;
|
||||||
use App\Models\PodcastModel;
|
use App\Models\PodcastModel;
|
||||||
|
use CodeIgniter\Files\File;
|
||||||
use CodeIgniter\HTTP\RedirectResponse;
|
use CodeIgniter\HTTP\RedirectResponse;
|
||||||
use PHP_ICO;
|
use PHP_ICO;
|
||||||
|
|
||||||
|
@ -156,6 +160,108 @@ class SettingsController extends BaseController
|
||||||
return redirect('settings-general')->with('message', lang('Settings.images.regenerationSuccess'));
|
return redirect('settings-general')->with('message', lang('Settings.images.regenerationSuccess'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function runHousekeeping(): RedirectResponse
|
||||||
|
{
|
||||||
|
helper('media');
|
||||||
|
|
||||||
|
// Delete all podcast image sizes to recreate them
|
||||||
|
$allPodcasts = (new PodcastModel())->findAll();
|
||||||
|
foreach ($allPodcasts as $podcast) {
|
||||||
|
$podcastImages = glob(
|
||||||
|
ROOTPATH . 'public/' . config('App')->mediaRoot . "/podcasts/{$podcast->handle}/*_*{jpg,png,webp}",
|
||||||
|
GLOB_BRACE
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($podcastImages) {
|
||||||
|
foreach ($podcastImages as $podcastImage) {
|
||||||
|
if (is_file($podcastImage)) {
|
||||||
|
unlink($podcastImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all person image sizes to recreate them
|
||||||
|
$personsImages = glob(
|
||||||
|
ROOTPATH . 'public/' . config('App')->mediaRoot . '/persons/*_*{jpg,png,webp}',
|
||||||
|
GLOB_BRACE
|
||||||
|
);
|
||||||
|
if ($personsImages) {
|
||||||
|
foreach ($personsImages as $personsImage) {
|
||||||
|
if (is_file($personsImage)) {
|
||||||
|
unlink($personsImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$allImages = (new MediaModel('image'))->getAllOfType();
|
||||||
|
foreach ($allImages as $image) {
|
||||||
|
if (str_starts_with($image->file_path, 'podcasts')) {
|
||||||
|
if (str_ends_with($image->file_path, 'banner.jpg') || str_ends_with($image->file_path, 'banner.png')) {
|
||||||
|
$image->sizes = config('Images')
|
||||||
|
->podcastBannerSizes;
|
||||||
|
} else {
|
||||||
|
$image->sizes = config('Images')
|
||||||
|
->podcastCoverSizes;
|
||||||
|
}
|
||||||
|
} elseif (str_starts_with($image->file_path, 'persons')) {
|
||||||
|
$image->sizes = config('Images')
|
||||||
|
->personAvatarSizes;
|
||||||
|
}
|
||||||
|
$image->setFile(new File(media_path($image->file_path)));
|
||||||
|
|
||||||
|
(new MediaModel('image'))->updateMedia($image);
|
||||||
|
}
|
||||||
|
|
||||||
|
$allAudio = (new MediaModel('audio'))->getAllOfType();
|
||||||
|
foreach ($allAudio as $audio) {
|
||||||
|
$audio->setFile(new File(media_path($audio->file_path)));
|
||||||
|
|
||||||
|
(new MediaModel('audio'))->updateMedia($audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
$allTranscripts = (new MediaModel('transcript'))->getAllOfType();
|
||||||
|
foreach ($allTranscripts as $transcript) {
|
||||||
|
$transcript->setFile(new File(media_path($transcript->file_path)));
|
||||||
|
|
||||||
|
(new MediaModel('transcript'))->updateMedia($transcript);
|
||||||
|
}
|
||||||
|
|
||||||
|
$allChapters = (new MediaModel('chapters'))->getAllOfType();
|
||||||
|
foreach ($allChapters as $chapters) {
|
||||||
|
$chapters->setFile(new File(media_path($chapters->file_path)));
|
||||||
|
|
||||||
|
(new MediaModel('chapters'))->updateMedia($chapters);
|
||||||
|
}
|
||||||
|
|
||||||
|
$allVideos = (new MediaModel('video'))->getAllOfType();
|
||||||
|
foreach ($allVideos as $video) {
|
||||||
|
$video->setFile(new File(media_path($video->file_path)));
|
||||||
|
|
||||||
|
(new MediaModel('video'))->updateMedia($video);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset avatar and banner image urls for each podcast actor
|
||||||
|
foreach ($allPodcasts as $podcast) {
|
||||||
|
$actorModel = new ActorModel();
|
||||||
|
$actor = $actorModel->getActorById($podcast->actor_id);
|
||||||
|
|
||||||
|
if ($actor !== null) {
|
||||||
|
// update values
|
||||||
|
$actor->avatar_image_url = $podcast->cover->federation_url;
|
||||||
|
$actor->avatar_image_mimetype = $podcast->cover->file_mimetype;
|
||||||
|
$actor->cover_image_url = $podcast->banner->federation_url;
|
||||||
|
$actor->cover_image_mimetype = $podcast->banner->file_mimetype;
|
||||||
|
|
||||||
|
if ($actor->hasChanged()) {
|
||||||
|
$actorModel->update($actor->id, $actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect('settings-general')->with('message', lang('Settings.housekeeping.runSuccess'));
|
||||||
|
}
|
||||||
|
|
||||||
public function theme(): string
|
public function theme(): string
|
||||||
{
|
{
|
||||||
helper('form');
|
helper('form');
|
||||||
|
|
|
@ -28,6 +28,12 @@ return [
|
||||||
'regenerate' => 'Regenerate images',
|
'regenerate' => 'Regenerate images',
|
||||||
'regenerationSuccess' => 'All images have been regenerated successfully!',
|
'regenerationSuccess' => 'All images have been regenerated successfully!',
|
||||||
],
|
],
|
||||||
|
'housekeeping' => [
|
||||||
|
'title' => 'Housekeeping',
|
||||||
|
'subtitle' => 'Runs various housekeeping tasks, such as rewriting media files metadata (images, audio files, transcripts, chapters, …).',
|
||||||
|
'run' => 'Run housekeeping',
|
||||||
|
'runSuccess' => 'Housekeeping has been run successfully!',
|
||||||
|
],
|
||||||
'theme' => [
|
'theme' => [
|
||||||
'title' => 'Theme',
|
'title' => 'Theme',
|
||||||
'accent_section_title' => 'Accent color',
|
'accent_section_title' => 'Accent color',
|
||||||
|
|
|
@ -28,6 +28,12 @@ return [
|
||||||
'regenerate' => 'Regénérer les images',
|
'regenerate' => 'Regénérer les images',
|
||||||
'regenerationSuccess' => 'Toutes les images ont été regénérés avec succès !',
|
'regenerationSuccess' => 'Toutes les images ont été regénérés avec succès !',
|
||||||
],
|
],
|
||||||
|
'housekeeping' => [
|
||||||
|
'title' => 'Ménage',
|
||||||
|
'subtitle' => 'Exécute un nombre de tâches de nettoyage, comme la réécriture de métadonnées des fichiers media (images, fichiers audio, transcript, chapitres, …).',
|
||||||
|
'run' => 'Faire le ménage',
|
||||||
|
'runSuccess' => 'Le ménage a été effectué avec succès !',
|
||||||
|
],
|
||||||
'theme' => [
|
'theme' => [
|
||||||
'title' => 'Thème',
|
'title' => 'Thème',
|
||||||
'accent_section_title' => 'Couleur d’accentuation',
|
'accent_section_title' => 'Couleur d’accentuation',
|
||||||
|
|
|
@ -69,6 +69,20 @@
|
||||||
</Forms.Section>
|
</Forms.Section>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form action="<?= route_to('settings-housekeeping-run') ?>" method="POST" class="flex flex-col max-w-xl gap-y-4">
|
||||||
|
<?= csrf_field() ?>
|
||||||
|
|
||||||
|
<Forms.Section
|
||||||
|
title="<?= lang('Settings.housekeeping.title') ?>"
|
||||||
|
subtitle="<?= lang('Settings.housekeeping.subtitle') ?>" >
|
||||||
|
|
||||||
|
<Button variant="primary" type="submit" iconLeft="home-gear"><?= lang('Settings.housekeeping.run') ?></Button>
|
||||||
|
|
||||||
|
</Forms.Section>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= $this->endSection() ?>
|
<?= $this->endSection() ?>
|
||||||
|
|
Loading…
Reference in New Issue