# movmaker-webui

A small PHP web interface for publishing and managing **MVLog** videos on Bubulescu.Org.

The app has two sides:

- **Public landing page**: lists rendered videos from `out-dir/`.
- **Admin page**: creates and edits movmaker input directories in `in-dir/`.

Generated videos are rendered by the separate `movmaker` worker script and published back into this web app.

## Paths and URLs

Production location:

```text
/var/www/html/mvlog
```

Public URLs:

```text
https://bubulescu.org/mvlog/
https://bubulescu.org/mvlog/new.php
https://bubulescu.org/mvlog/login.php
https://bubulescu.org/mvlog/feed.php
```

Important directories:

```text
in-dir/       Admin-created movmaker input directories
out-dir/      Rendered public videos
cache/        Cached video metadata
assets/       CSS assets, background image, fonts
thumbs/       Reserved for thumbnails
```

## Main files

```text
index.php     Public video landing page
new.php       Protected admin interface
login.php     PHP session login page
logout.php    Destroys admin session and redirects to login
feed.php      RSS feed of latest videos
auth.php      PHP session authentication helpers
config.php    Main app config
style.css     Site/admin styling
```

## Features

### Public landing page

`index.php` lists videos from `out-dir/`.

Features:

- Dark cinematic MVLog theme
- Sticky compact header
- RSS icon in the header
- One video per row
- Metadata display:
  - title
  - event date from embedded metadata
  - location when available
  - description when available
  - video creation/publish timestamp in the top-right corner of each row
- Download discouraged with:
  - `controlsList="nodownload"`
  - right-click disabled on videos
- Video metadata cached in `cache/videos.json`

### RSS feed

`feed.php` exposes an RSS feed of recent videos:

```text
https://bubulescu.org/mvlog/feed.php
```

The feed includes video title, link, description, publication date, and video enclosure.

### New badges

Recent videos can be styled with a `New` badge. The CSS class is:

```css
.new-badge
```

### Admin page

`new.php` is protected by PHP session login.

Admin tabs:

- **New**: create a new input directory
- **Edit**: edit existing input directories
- **Videos**: manage orphan videos not referenced by `.movmaker-state.json`

Admin can:

- Create input dirs
- Upload images/videos/audio
- Edit metadata
- Edit per-file captions for images/videos
- Remove media files
- Delete input dirs
- Optionally delete the generated output video associated with an input dir
- Delete orphan videos

Internal files such as `.movmaker-state.json` and `data.txt` are not shown as removable media files.

## Authentication

The admin area uses PHP sessions, not nginx Basic Auth.

Auth files:

```text
/var/www/html/mvlog/auth.php
/etc/mvlog/auth.php
```

`/etc/mvlog/auth.php` stores username/password hashes outside the web root:

```php
<?php
return [
    'users' => [
        'username' => 'password_hash_here',
    ],
];
```

The password hash should be generated with PHP `password_hash()`.

Example:

```bash
php -r 'echo password_hash("new-password", PASSWORD_DEFAULT), PHP_EOL;'
```

Then update `/etc/mvlog/auth.php`.

Logout:

```text
/mvlog/logout.php
```

Logout destroys the PHP session and redirects to `login.php`.

## Input directory naming

New admin-created input directories must use:

```text
YYYYMMDD_slug-title
```

Example:

```text
20260525_mohnesee
```

Do **not** include time in the directory name.

## `data.txt` format

Each input directory contains a `data.txt` file.

All entries use mandatory `key: value` syntax:

```text
Title: My Movie Title
Location: Sønderborg
Date: 2026-05-25
Description: Short description of the video.
filename.jpg: Optional caption for this file
filename.mp4: Optional caption for this clip
```

Supported general keys:

```text
Title
Location
Date
Description
```

Per-file captions are stored as:

```text
filename.ext: caption text
```

Audio files do not get captions in the admin UI.

## Worker integration

Rendering is handled by the separate `movmaker` project, especially:

```text
/home/hbrain/source/movmaker/mvlog_worker.py
```

The worker:

1. Scans remote `in-dir/` directories.
2. Computes an input fingerprint.
3. Compares with `.movmaker-state.json`.
4. Renders changed jobs with `movmaker.py`.
5. Publishes MP4 files to `out-dir/`.
6. Updates `.movmaker-state.json`.
7. Clears `cache/videos.json` after publishing.

State file per input dir:

```text
in-dir/<job>/.movmaker-state.json
```

The state file maps an input dir to its generated output video. Orphan detection must rely on this state file only.

Systemd units on the worker machine:

```text
/etc/systemd/system/mvlog-worker.service
/etc/systemd/system/mvlog-worker.timer
```

Useful commands:

```bash
systemctl status mvlog-worker.service --no-pager
systemctl status mvlog-worker.timer --no-pager
journalctl -u mvlog-worker.service -n 100 --no-pager
```

## Orphan video handling

The admin **Videos** tab shows generated videos in `out-dir/` that are not referenced by any input directory state file.

Important rule:

> Orphan detection must use `.movmaker-state.json` only. Do not infer ownership from metadata or title fallback.

## Configuration

`config.php` returns the main app config:

```php
return [
    "site_name" => "Movmaker WebUI",
    "videos_dir" => __DIR__ . "/out-dir",
    "thumbs_dir" => __DIR__ . "/thumbs",
    "uploads_dir" => __DIR__ . "/in-dir",
    "public_videos" => "out-dir",
    "public_thumbs" => "thumbs",
    "items_per_page" => 12,
];
```

## nginx/PHP requirements

The app runs under nginx + PHP-FPM.

Admin uploads require larger request limits. Production currently uses:

```nginx
client_max_body_size 512M;
```

PHP-FPM upload override:

```ini
upload_max_filesize = 512M
post_max_size = 512M
max_file_uploads = 100
max_input_time = 600
max_execution_time = 600
```

Example file:

```text
/etc/php/8.2/fpm/conf.d/99-mvlog-upload.ini
```

After changing nginx/PHP config:

```bash
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl restart php8.2-fpm
```

## Timezone

The public page and RSS feed explicitly use:

```php
date_default_timezone_set('Europe/Copenhagen');
```

This ensures displayed creation/publish times are Danish local time, not UTC.

## Permissions

Expected web ownership is generally:

```text
www-data:www-data
```

The git repo may be owned by `hbrain:www-data`.

State files should be group-writable so the worker can update them:

```bash
chmod 664 in-dir/*/.movmaker-state.json
```

The worker writes state files using a temp file and `chmod 664` to avoid permission problems.

## Git notes

Repository:

```text
https://git.novosel.dk/marijo/movmaker-webui.git
```

If git complains about ownership:

```bash
git config --global --add safe.directory /var/www/html/mvlog
sudo chown -R hbrain:www-data /var/www/html/mvlog/.git
```

Do not commit generated media from `in-dir/` or `out-dir/`.

`AGENTS.md` is local assistant/project context and should remain ignored by git.
