first commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# Home video organizer: phase 1
|
||||
|
||||
This Python command scans a folder of videos recursively. It groups clips by filming date, excludes clips shorter than 5 seconds from the output, makes a LosslessCut `.llc` project for every clip longer than 3 minutes, and writes one chronologically sorted JSON manifest per day. Each manifest has an editable `title` string and a `videos` array. Source videos are never deleted or modified. A clip exactly 5 seconds long is included; a clip exactly 180 seconds long remains a video entry.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.9 or newer
|
||||
- FFmpeg's `ffprobe` on your PATH
|
||||
- LosslessCut to review/edit the generated `.llc` projects
|
||||
- On Windows, if IANA timezones are unavailable: `py -m pip install tzdata`
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
python home_video_phase1.py "/path/to/all-videos" "/path/to/day-output" --timezone America/New_York
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```powershell
|
||||
py home_video_phase1.py "D:\Home Videos" "D:\Video Days" --timezone America/New_York
|
||||
```
|
||||
|
||||
For one date, add `--date 2024-07-11`. The output directory must be outside the input directory. If the video has neither a recognized embedded recording date nor a date in its filename, the script skips it with a message. Use `--fallback mtime` if you want such files assigned by filesystem modification time (which can change when copying files).
|
||||
|
||||
## Date and ordering
|
||||
|
||||
The command uses the file's embedded QuickTime `com.apple.quicktime.creationdate` or `creation_time` when available, then a `YYYYMMDD[_HHMMSS]` or `YYYY-MM-DD[_HH-MM-SS]` style filename. Date-only filenames are placed at midnight, with the path used to break ties. Embedded UTC dates are converted to `--timezone` before grouping and sorting. Choose the timezone where the videos were filmed. If the cameras have wrong clocks, correct their metadata or names before running the command.
|
||||
|
||||
## Output
|
||||
|
||||
For example, `2024-07-11.json` contains a title and an array of absolute paths:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "",
|
||||
"videos": [
|
||||
"/path/to/day-output/projects/2024-07-11/long-3f7a4c5d12.llc",
|
||||
"/path/to/all-videos/shorter.mp4"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The generated `.llc` project contains the absolute source path and one selected segment covering the whole video. Review long videos in LosslessCut to mark cuts. Set `title` when you have chosen a rendered-video title; rerunning the command preserves that string while updating `videos`. Existing array-format manifests are upgraded on the next run with an empty title. Files that fail probing or date detection are reported and cause a nonzero exit code; already successful days are still written.
|
||||
|
||||
## Review titles
|
||||
|
||||
Install the lightweight Python VLC binding into the Python environment used for the tool:
|
||||
|
||||
```powershell
|
||||
py -m pip install -r requirements-review.txt
|
||||
```
|
||||
|
||||
Open a daily manifest in the Tkinter reviewer:
|
||||
|
||||
```powershell
|
||||
py review_videos.py "D:\Video Days\2024-07-11.json"
|
||||
```
|
||||
|
||||
The reviewer uses the portable VLC installation at `C:\PortableApps\VLCPortable3` by default. Pass `--vlc-dir` or set `VLC_DIR` if it is elsewhere. VLC and Python must have matching architectures (both 64-bit, for example). It plays the source video for each entry, including the `mediaFileName` referenced by `.llc` projects; it does not apply LosslessCut edits. Use `j`/`l` to seek back/forward 10 seconds, Left/Right to change videos, and Space to pause or resume. Playback automatically starts the next manifest entry when a video ends. The title saves automatically to the manifest. Click the title box to edit; click elsewhere in the reviewer to return keyboard control to playback. Legacy array manifests are accepted and converted to the object format when saved.
|
||||
|
||||
## Render titled daily videos
|
||||
|
||||
After filling in a manifest title, render all titled daily manifests in `out/`:
|
||||
|
||||
```powershell
|
||||
py render_daily_videos.py
|
||||
```
|
||||
|
||||
The script saves one MP4 per manifest under `out\rendered` by default. Pass a different manifest folder as the first argument (for example, `py render_daily_videos.py "D:\Video Days"`) and choose another destination with `--output-dir`. Untitled manifests are skipped. Existing output files are preserved unless `--overwrite` is supplied.
|
||||
|
||||
Videos are processed in manifest order. Raw video paths use the full clip; `.llc` entries use their `mediaFileName` and the time ranges in `cutSegments` (a project with no ranges uses the full clip). Before rendering, the script probes every source, uses the highest frame rate it finds, and chooses the largest source resolution by pixel area (ties go to the wider source). It accounts for 90-degree rotation metadata. Other clips are scaled and padded to fit that output canvas. The renderer crossfades video and audio over 1.5 seconds and fades the video and audio in and out over 1.5 seconds. The trimmed manifest title starts fading in at 3 seconds, stays fully visible for 5 seconds, then fades out; each title fade lasts 0.75 seconds. At the bottom right, it shows the manifest date (formatted like `December 25, 2025`) above the title, with both lines left aligned and no text box. The title uses `C:\Windows\Fonts\MVBOLI.TTF` (MV Boli). Timing, font, fallback frame rate (30 fps if the sources report none), and encoder settings are constants near the top of `render_daily_videos.py`.
|
||||
|
||||
FFmpeg and `ffprobe` must be available on `PATH`; FFmpeg must include the `drawtext` filter. Rendering tries NVIDIA's `h264_nvenc` encoder first and falls back to `libx264` if NVENC is unavailable or fails. NVENC accelerates video encoding; the crossfade, scaling, and title filters run through FFmpeg's CPU filters.
|
||||
|
||||
An SVG can be used as a designed title template, but this FFmpeg build has no SVG decoder, so the SVG would first need to be rasterized to an image for each manifest. For the current two-line date/title overlay, `drawtext` keeps the workflow simpler. An SVG becomes useful if the title needs more elaborate graphics or decorative layout.
|
||||
|
||||
**Compatibility note:** `.llc` files use LosslessCut's version 2 project structure (`mediaFileName`, `cutSegments`). Check one generated project in your installed LosslessCut version before working through a large collection.
|
||||
Reference in New Issue
Block a user