Updating with new features
This commit is contained in:
parent
6a152e21b4
commit
4b1b8ccd42
1 changed files with 124 additions and 531 deletions
655
README.md
655
README.md
|
|
@ -1,538 +1,131 @@
|
||||||
# movmaker-webui
|
# movmaker-webui (MVL)
|
||||||
|
|
||||||
A small PHP web interface for publishing and managing **MVLog** videos on Bubulescu.Org.
|
PHP web UI for publishing and managing MVLog videos on **bubulescu.org**.
|
||||||
|
|
||||||
The app has two sides:
|
## Production location
|
||||||
|
|
||||||
- **Public landing page**: lists rendered videos from `out-dir/`.
|
- Web root: `/var/www/html/mvlog`
|
||||||
- **Admin page**: creates and edits movmaker input directories in `in-dir/`.
|
- Public URLs:
|
||||||
|
- `https://bubulescu.org/`
|
||||||
Generated videos are rendered by the separate `movmaker` worker script and published back into this web app.
|
- `https://bubulescu.org/new.php`
|
||||||
|
- `https://bubulescu.org/login.php`
|
||||||
## Paths and URLs
|
- `https://bubulescu.org/feed.php`
|
||||||
|
- `https://bubulescu.org/contact.php`
|
||||||
Production location:
|
|
||||||
|
## Main structure
|
||||||
```text
|
|
||||||
/var/www/html/mvlog
|
- `index.php` — public landing page (rendered videos)
|
||||||
```
|
- `new.php` — authenticated admin UI
|
||||||
|
- `feed.php` — RSS feed
|
||||||
Public URLs:
|
- `contact.php` — contact form
|
||||||
|
- `auth.php` — session auth helpers
|
||||||
```text
|
- `config.php` — app config
|
||||||
https://bubulescu.org/
|
- `style.css` — shared styles
|
||||||
https://bubulescu.org/new.php
|
- `_header.php`, `_footer.php`, `_footer_admin.php` — shared layout includes
|
||||||
https://bubulescu.org/login.php
|
|
||||||
https://bubulescu.org/feed.php
|
Important dirs:
|
||||||
https://bubulescu.org/contact.php
|
|
||||||
```
|
- `in-dir/` — input/article dirs
|
||||||
|
- `out-dir/` — rendered videos
|
||||||
Important directories:
|
- `thumbs/` — custom video poster images
|
||||||
|
- `cache/` — metadata/search/push caches
|
||||||
```text
|
|
||||||
in-dir/ Admin-created movmaker input directories
|
## Public page (`index.php`)
|
||||||
out-dir/ Rendered public videos
|
|
||||||
cache/ Cached video metadata
|
- Randomized header title text (`<h1>`), fixed HTML title `MVL`
|
||||||
assets/ CSS assets, background image, fonts
|
- Header actions: notifications, RSS, contact
|
||||||
thumbs/ Reserved for thumbnails
|
- Search supports:
|
||||||
```
|
- general keyword (title/teaser/quote_da/description)
|
||||||
|
- `date=...`
|
||||||
## Main files
|
- `location=...` / `place=...`
|
||||||
|
- Case-insensitive + accent-insensitive matching
|
||||||
```text
|
- Shows title/date/location/teaser/description/quote_da
|
||||||
index.php Public video landing page
|
- **No generated timestamp is shown on cards**
|
||||||
new.php Protected admin interface
|
- Optional map image per video (hidden when source article has `.mvlog-hide-map`)
|
||||||
login.php PHP session login page
|
- Optional custom video poster from `thumbs/`
|
||||||
logout.php Destroys admin session and redirects to login
|
|
||||||
feed.php RSS feed of latest videos
|
## Admin (`new.php`)
|
||||||
auth.php PHP session authentication helpers
|
|
||||||
config.php Main app config
|
Requires login via PHP session.
|
||||||
style.css Site/admin styling
|
|
||||||
```
|
Tabs:
|
||||||
|
- **New** — create input dirs + upload media
|
||||||
## Features
|
- **Edit** — edit metadata/media/order/toggles
|
||||||
|
- **Videos** — manage orphan output videos
|
||||||
### Public landing page
|
|
||||||
|
Implemented behavior:
|
||||||
`index.php` lists videos from `out-dir/`.
|
|
||||||
|
- Article identity uses `.mvlog-id` (immutable ID), with legacy dir-name fallback
|
||||||
Features:
|
- Draft metadata is read/written from `in-dir/<job>/data.txt`
|
||||||
|
- Supports metadata fields: `title`, `teaser`, `quote_da`, `date`, `place`, `description`
|
||||||
- Dark cinematic MVLog theme
|
- Manual media reordering via `order.json` (AJAX action `reorder_file`)
|
||||||
- Sticky compact header
|
- Per-article toggles:
|
||||||
- Compact stacked header actions: notifications, RSS, contact
|
- Preview (`set_preview`)
|
||||||
- One video per row
|
- Render (`set_enabled`)
|
||||||
- Metadata display:
|
- Show (`set_visible`)
|
||||||
- title
|
- Hide map (`set_map_hidden` -> `.mvlog-hide-map`)
|
||||||
- event date from embedded metadata
|
- Custom video poster selection from input images (`set_video_thumb`)
|
||||||
- location when available
|
- Describe button uses `lib/generate_data_sync.php`
|
||||||
- description when available
|
- Job status polling via `job_status.php` every 32s
|
||||||
- video creation/publish timestamp in the top-right corner of each row
|
|
||||||
- Download discouraged with:
|
## Ordering rules
|
||||||
- `controlsList="nodownload"`
|
|
||||||
- right-click disabled on videos
|
For visual media ordering in admin/render flow:
|
||||||
- Video metadata cached in `cache/videos.json`
|
1. `order.json` (authoritative when present)
|
||||||
|
2. embedded metadata datetime
|
||||||
### Contact page
|
3. filename datetime
|
||||||
|
4. filesystem datetime
|
||||||
`contact.php` provides a simple contact form (name, email, message) with a honeypot field.
|
|
||||||
|
`order.json` is web/admin-owned (worker consumes it).
|
||||||
Mail recipient config:
|
|
||||||
|
## Contact form (`contact.php`)
|
||||||
```php
|
|
||||||
// /var/www/html/mvlog/contact.php
|
- Fields: name, email, message + honeypot anti-spam field
|
||||||
$to_email = 'your-real-email@example.com';
|
- Uses PHP `mail()`
|
||||||
```
|
- On success: redirects to `https://bubulescu.org/`
|
||||||
|
- Recipient is configured in `contact.php` (`$to_email`)
|
||||||
Replace that with the real recipient address.
|
|
||||||
|
## Push notifications
|
||||||
The form uses PHP `mail()`, so server mail delivery must be configured (sendmail/postfix/msmtp or equivalent).
|
|
||||||
|
Files:
|
||||||
### RSS feed
|
- `push_config.php` — exposes only public VAPID key
|
||||||
|
- `push_subscribe.php` — stores subscriptions in `cache/push_subscriptions.json`
|
||||||
`feed.php` exposes an RSS feed of recent videos:
|
- `lib/send_push.php` + `send_push.js` — server-side send logic
|
||||||
|
- `api/enable_show.php` — triggers push on Show enable
|
||||||
```text
|
- `sw.js` — service worker fallback notification text
|
||||||
https://bubulescu.org/feed.php
|
|
||||||
```
|
Current text behavior:
|
||||||
|
- payload body: `New aticle @ MVL!`
|
||||||
The feed includes video title, link, description, publication date, and video enclosure.
|
- SW fallback title/body: `MVL` / `New article @ MVL!`
|
||||||
|
|
||||||
### New badges
|
Push config is loaded from first available:
|
||||||
|
- `/etc/mvlog/push.php`
|
||||||
Recent videos can be styled with a `New` badge. The CSS class is:
|
- `/etc/mvlog/push.json`
|
||||||
|
- `/var/www/html/mvlog/push.json`
|
||||||
```css
|
- `~/.config/mvlog/push.json`
|
||||||
.new-badge
|
|
||||||
```
|
## Auth
|
||||||
|
|
||||||
### Admin page
|
- Session cookie name: `MVLOGSESSID`
|
||||||
|
- Cookie path: `/`
|
||||||
`new.php` is protected by PHP session login.
|
- Auth config: `/etc/mvlog/auth.php`
|
||||||
|
|
||||||
Admin tabs:
|
## Runtime config (`config.php`)
|
||||||
|
|
||||||
- **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
|
```php
|
||||||
return [
|
return [
|
||||||
"site_name" => "Movmaker WebUI",
|
"site_name" => "Admin MVLog",
|
||||||
"videos_dir" => __DIR__ . "/out-dir",
|
"videos_dir" => __DIR__ . "/out-dir",
|
||||||
"thumbs_dir" => __DIR__ . "/thumbs",
|
"thumbs_dir" => __DIR__ . "/thumbs",
|
||||||
"uploads_dir" => __DIR__ . "/in-dir",
|
"uploads_dir" => __DIR__ . "/in-dir",
|
||||||
"public_videos" => "out-dir",
|
"public_videos" => "out-dir",
|
||||||
"public_thumbs" => "thumbs",
|
"public_thumbs" => "thumbs",
|
||||||
"items_per_page" => 12,
|
"items_per_page" => 8,
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
## nginx/PHP requirements
|
## Notes
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Server-side web-push notifications
|
|
||||||
|
|
||||||
The MVLog web UI includes a small server-side push integration so the admin can immediately notify subscribers when a job is made "Show". Keys and sending logic live on the webserver to keep VAPID private keys secret and to avoid exposing them to worker nodes.
|
|
||||||
|
|
||||||
Key files and behavior (deployed under /var/www/html/mvlog):
|
|
||||||
|
|
||||||
- lib/send_push.php — PHP helper that invokes the Node sender and atomically records send state in cache/push_notifications.json.
|
|
||||||
- send_push.js — Node script (uses the package) to send individual push messages; it reads subscriptions and push config and performs sends.
|
|
||||||
- cache/push_subscriptions.json — stored subscriber list (array of subscription objects).
|
|
||||||
- cache/push_notifications.json — recorded sends (shown map) to avoid duplicate notifications.
|
|
||||||
- api/enable_show.php — authenticated endpoint to toggle Show and trigger a server-side send (requires admin login).
|
|
||||||
- new.php — admin UI now triggers the server-side helper when Show is enabled.
|
|
||||||
- /etc/mvlog/push.php or /var/www/html/mvlog/push.json — VAPID key holder (private key must remain secret; set owner to root or www-data and permissions to 600/640).
|
|
||||||
- log: /var/log/mvlog_notify.log — send attempts and errors are logged here.
|
|
||||||
|
|
||||||
Installation notes:
|
|
||||||
|
|
||||||
1. Install Node and web-push in the webroot:
|
|
||||||
|
|
||||||
npm install web-push --prefix /var/www/html/mvlog
|
|
||||||
|
|
||||||
2. Place VAPID keys where the webserver can read them (recommended: /etc/mvlog/push.php) and set restrictive permissions (600 or 640, owner root:www-data). Do NOT commit private keys to git.
|
|
||||||
|
|
||||||
3. Ensure /var/www/html/mvlog/cache exists and contains push_subscriptions.json and push_notifications.json (create {} if empty), owned by www-data and writable.
|
|
||||||
|
|
||||||
Security notes:
|
|
||||||
|
|
||||||
- api/enable_show.php requires admin login; do not expose it publicly without strong auth.
|
|
||||||
- Consider adding CSRF protection, rate limiting, and periodic pruning of expired subscriptions (HTTP 410 responses) to reduce send failures.
|
|
||||||
|
|
||||||
|
|
||||||
## Gemini-based description generator
|
|
||||||
|
|
||||||
A helper script on the webserver can analyze an input directory (images/videos) and produce a short JSON description using the Google Generative Language (Gemini) API.
|
|
||||||
|
|
||||||
- Script: /var/www/html/mvlog/bin/generate_data.sh
|
|
||||||
- Purpose: collect representative frames, call Gemini, save the raw response as <inputdir>/gemini_generated.json, and append a Description block to <inputdir>/data.txt only if no Description already exists.
|
|
||||||
|
|
||||||
What it does:
|
|
||||||
|
|
||||||
- Collects up to N frames from the input dir (images -> 1 frame, videos -> up to 3 frames depending on duration).
|
|
||||||
- Builds a JSON request containing the prompt and inline base64-encoded images using a Python helper to avoid ARG_MAX issues.
|
|
||||||
- Calls the Gemini API and saves the returned JSON text to <inputdir>/gemini_generated.json for review.
|
|
||||||
- Appends only a Description block (Description:
|
|
||||||
## Server-side web-push notifications
|
|
||||||
|
|
||||||
The MVLog web UI includes a small server-side push integration so the admin can immediately notify subscribers when a job is made "Show". Keys and sending logic live on the webserver to keep VAPID private keys secret and to avoid exposing them to worker nodes.
|
|
||||||
|
|
||||||
Key files and behavior (deployed under /var/www/html/mvlog):
|
|
||||||
|
|
||||||
- lib/send_push.php — PHP helper that invokes the Node sender and atomically records send state in cache/push_notifications.json.
|
|
||||||
- send_push.js — Node script (uses the `web-push` package) to send individual push messages; it reads subscriptions and push config and performs sends.
|
|
||||||
- cache/push_subscriptions.json — stored subscriber list (array of subscription objects).
|
|
||||||
- cache/push_notifications.json — recorded sends ("shown" map) to avoid duplicate notifications.
|
|
||||||
- api/enable_show.php — authenticated endpoint to toggle Show and trigger a server-side send (requires admin login).
|
|
||||||
- new.php — admin UI now triggers the server-side helper when Show is enabled.
|
|
||||||
- /etc/mvlog/push.php or /var/www/html/mvlog/push.json — VAPID key holder (private key must remain secret; set owner to root or www-data and permissions to 600/640).
|
|
||||||
- log: /var/log/mvlog_notify.log — send attempts and errors are logged here.
|
|
||||||
|
|
||||||
Installation notes:
|
|
||||||
|
|
||||||
1. Install Node and web-push in the webroot:
|
|
||||||
|
|
||||||
npm install web-push --prefix /var/www/html/mvlog
|
|
||||||
|
|
||||||
2. Place VAPID keys where the webserver can read them (recommended: /etc/mvlog/push.php) and set restrictive permissions (600 or 640, owner root:www-data). Do NOT commit private keys to git.
|
|
||||||
|
|
||||||
3. Ensure /var/www/html/mvlog/cache exists and contains push_subscriptions.json and push_notifications.json (create {} if empty), owned by www-data and writable.
|
|
||||||
|
|
||||||
Security notes:
|
|
||||||
|
|
||||||
- api/enable_show.php requires admin login; do not expose it publicly without strong auth.
|
|
||||||
- Consider adding CSRF protection, rate limiting, and periodic pruning of expired subscriptions (HTTP 410 responses) to reduce send failures.
|
|
||||||
|
|
||||||
|
|
||||||
## Gemini-based description generator
|
|
||||||
|
|
||||||
A helper script on the webserver can analyze an input directory (images/videos) and produce a short JSON description using the Google Generative Language (Gemini) API.
|
|
||||||
|
|
||||||
- Script: /var/www/html/mvlog/bin/generate_data.sh
|
|
||||||
- Purpose: collect representative frames, call Gemini, save the raw response as <inputdir>/gemini_generated.json, and append a Description block to <inputdir>/data.txt only if no Description already exists.
|
|
||||||
|
|
||||||
What it does:
|
|
||||||
|
|
||||||
- Collects up to N frames from the input dir (images -> 1 frame, videos -> up to 3 frames depending on duration).
|
|
||||||
- Builds a JSON request containing the prompt and inline base64-encoded images using a Python helper to avoid ARG_MAX issues.
|
|
||||||
- Calls the Gemini API and saves the returned JSON text to <inputdir>/gemini_generated.json for review.
|
|
||||||
- Appends only a Description block ("Description: |\n ...") to <inputdir>/data.txt if data.txt does not already contain a Description key (case-insensitive). It never changes other keys in data.txt.
|
|
||||||
- Leaves gemini_generated.json unchanged (always written as the raw response).
|
|
||||||
|
|
||||||
Configuration and requirements:
|
|
||||||
|
|
||||||
- GEMINI_API_KEY should be placed in /etc/mvlog/gemini.env and be readable by www-data (recommended owner root:www-data mode 640).
|
|
||||||
- Required tools on the webserver: jq, python3, ffmpeg, ffprobe, curl.
|
|
||||||
- Run the script as the webserver user so created files are owned by www-data and permissions are correct:
|
|
||||||
|
|
||||||
sudo -u www-data /var/www/html/mvlog/bin/generate_data.sh /var/www/html/mvlog/in-dir/20230630_napoli "Naples" "Naples, Italy" 8
|
|
||||||
|
|
||||||
Troubleshooting:
|
|
||||||
|
|
||||||
- If Gemini returns HTTP 429 RESOURCE_EXHAUSTED, ensure the API key is attached to a project with billing and the Generative Language API quota enabled.
|
|
||||||
- If you see "Argument list too long" errors, ensure generate_data.sh is the deployed version that uses the Python builder (it avoids embedding large base64 arguments directly into jq/curl).
|
|
||||||
- Run the script as www-data to avoid permission problems reading /etc/mvlog/gemini.env and to create files owned by the webserver.
|
|
||||||
|
|
||||||
## Admin Describe UI & synchronous generator
|
|
||||||
|
|
||||||
The admin interface includes a new "Describe" button on each input-dir row (Edit tab). Clicking it runs a server-side synchronous helper which invokes the Gemini-based generator in "no-append" mode and returns the generated description in a popup. From the popup you can choose "Use in form" to copy the description into the edit form's Description textarea. The description is written to disk only when you click "Save changes" in the edit form.
|
|
||||||
|
|
||||||
Server-side helper:
|
|
||||||
|
|
||||||
- lib/generate_data_sync.php — authenticated endpoint used by the admin UI. It runs bin/generate_data.sh with a trailing `no-append` argument so data.txt is not modified automatically and returns the generated JSON/description to the browser.
|
|
||||||
|
|
||||||
Script usage (no-append, run as the web user):
|
|
||||||
|
|
||||||
sudo -u www-data /var/www/html/mvlog/bin/generate_data.sh /var/www/html/mvlog/in-dir/20230630_napoli "Naples" "Naples, Italy" 16 no-append
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The admin UI uses 16 sample frames by default when requesting a description.
|
|
||||||
- The generator always writes the raw AI output to `<inputdir>/gemini_generated.json`. During debug runs the request/response may be saved as `debug_request.json`/`debug_response.json` inside the input dir for inspection.
|
|
||||||
- If the Gemini API returns an error (HTTP 429 or 503) the response and details are written to the job log (`<inputdir>/generate_data.log`) and debug response file when available.
|
|
||||||
|
|
||||||
If you prefer a background/async workflow instead of the synchronous popup, the endpoint and UI can be adjusted to start the job in the background and poll for results instead.
|
|
||||||
|
|
||||||
## Admin Describe UI & synchronous generator
|
|
||||||
|
|
||||||
The admin interface includes a new "Describe" button on each input-dir row (Edit tab). Clicking it runs a server-side synchronous helper which invokes the Gemini-based generator in "no-append" mode and returns the generated description in a popup. From the popup you can choose "Use in form" to copy the description into the edit form's Description textarea. The description is written to disk only when you click "Save changes" in the edit form.
|
|
||||||
|
|
||||||
Server-side helper:
|
|
||||||
|
|
||||||
- lib/generate_data_sync.php — authenticated endpoint used by the admin UI. It runs bin/generate_data.sh with a trailing `no-append` argument so data.txt is not modified automatically and returns the generated JSON/description to the browser.
|
|
||||||
|
|
||||||
Script usage (no-append, run as the web user):
|
|
||||||
|
|
||||||
sudo -u www-data /var/www/html/mvlog/bin/generate_data.sh /var/www/html/mvlog/in-dir/20230630_napoli "Naples" "Naples, Italy" 16 no-append
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The admin UI uses 16 sample frames by default when requesting a description.
|
|
||||||
- The generator always writes the raw AI output to `<inputdir>/gemini_generated.json`. During debug runs the request/response may be saved as `debug_request.json`/`debug_response.json` inside the input dir for inspection.
|
|
||||||
- If the Gemini API returns an error (HTTP 429 or 503) the response and details are written to the job log (`<inputdir>/generate_data.log`) and debug response file when available.
|
|
||||||
|
|
||||||
If you prefer a background/async workflow instead of the synchronous popup, the endpoint and UI can be adjusted to start the job in the background and poll for results instead.
|
|
||||||
|
|
||||||
## Admin Describe UI & synchronous generator
|
|
||||||
|
|
||||||
The admin interface includes a new "Describe" button on each input-dir row (Edit tab). Clicking it runs a server-side synchronous helper which invokes the Gemini-based generator in "no-append" mode and returns the generated description in a popup. From the popup you can choose "Use in form" to copy the description into the edit form's Description textarea. The description is written to disk only when you click "Save changes" in the edit form.
|
|
||||||
|
|
||||||
Server-side helper:
|
|
||||||
|
|
||||||
- lib/generate_data_sync.php — authenticated endpoint used by the admin UI. It runs bin/generate_data.sh with a trailing `no-append` argument so data.txt is not modified automatically and returns the generated JSON/description to the browser.
|
|
||||||
|
|
||||||
Script usage (no-append, run as the web user):
|
|
||||||
|
|
||||||
sudo -u www-data /var/www/html/mvlog/bin/generate_data.sh /var/www/html/mvlog/in-dir/20230630_napoli "Naples" "Naples, Italy" 16 no-append
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The admin UI uses 16 sample frames by default when requesting a description.
|
|
||||||
- The generator always writes the raw AI output to `<inputdir>/gemini_generated.json`. During debug runs the request/response may be saved as `debug_request.json`/`debug_response.json` inside the input dir for inspection.
|
|
||||||
- If the Gemini API returns an error (HTTP 429 or 503) the response and details are written to the job log (`<inputdir>/generate_data.log`) and debug response file when available.
|
|
||||||
|
|
||||||
If you prefer a background/async workflow instead of the synchronous popup, the endpoint and UI can be adjusted to start the job in the background and poll for results instead.
|
|
||||||
|
|
||||||
|
|
||||||
Push VAPID keys (push.json)
|
|
||||||
|
|
||||||
- push.json contains the VAPID keys used by the server for web-push.
|
|
||||||
- Do NOT commit push.json to git. Use push.json.example as a template.
|
|
||||||
|
|
||||||
To install on the server (example):
|
|
||||||
|
|
||||||
sudo cp push.json.example push.json
|
|
||||||
sudo chown root:www-data push.json
|
|
||||||
sudo chmod 640 push.json
|
|
||||||
|
|
||||||
|
- `contact.php` is currently in `.gitignore`.
|
||||||
|
- Keep secrets out of git (`push.json`, private keys, auth secrets).
|
||||||
|
- Worker/rendering is handled by separate movmaker worker project.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue