Commit Graph
230 Commits
Author SHA1 Message Date
Claude 6b03ae73a3 gitignore: exclude crescent detection debug images
*_debug_standard.jpg and *_debug_crescent.jpg are generated by
test_crescent_detect.py and should not be tracked.

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
2026-05-03 23:35:13 +00:00
Claude 0a48771641 Add test_crescent_detect.py — crescent detection test script
Runs detect_moon() twice on the same frame (standard params, then crescent
params) and saves annotated debug images for each pass so you can see
exactly what each threshold finds.  Optionally renders the full composite
if detection passes and a reference moon image is supplied.

Usage:
  python3 test_crescent_detect.py FRAME.jpg
  python3 test_crescent_detect.py FRAME.jpg --ref MOON.jpg --when 2026-05-08T05:30Z --phase waning-crescent

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
2026-05-03 23:34:50 +00:00
Claude 29a864375b Add waxing/waning crescent phases; fix phase-shadow double-application
moon_detect.py
- detect_moon() accepts saturated_threshold / min_roundness / max_halo_ratio
  so crescent phases (dim, non-circular arc) can be detected with relaxed
  thresholds without changing defaults for full/quarter detection.

moon_phase.py
- crescent_times_in_range(): 2-hour scan returning the UTC moment illumination
  crosses a target fraction (default 28%) on the waxing or waning side.
  Used for scheduling just like phase_events_in_range() for named phases.

moon_composite.py
- Remove _apply_phase_shadow() from composite_full_moon.  NASA SVS Dial-a-Moon
  renders already include the correct terminator, libration and earthshine for
  the exact hour; applying the shadow on top double-darkened the unlit limb on
  every non-full phase.  The function stays available for callers that need it.

moon_phase_monthly.py
- Add waxing-crescent (🌒) and waning-crescent (🌘) to PHASE_SPEC.
  Timing via crescent_times_in_range(); scheduling identical to other phases.
- CRESCENT_* tuning constants (all overridable from sky-cam.conf):
    MOON_CRESCENT_TARGET_ILLUM   default 0.28
    MOON_CRESCENT_MIN_QUALITY    default 0.35
    MOON_CRESCENT_SATURATED_THR  default 180
    MOON_CRESCENT_MIN_ROUNDNESS  default 0.15
    MOON_CRESCENT_MAX_HALO_RATIO default 12.0
- run_phase() and auto_run() branch on spec['crescent'] to use crescent
  timing and detection params.
- Atmospheric background naturally captures twilight colours (dawn for waning
  crescent, dusk/dawn for waxing) from the real east frame.

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
2026-05-03 23:21:44 +00:00
Claude b21803151b composite: add unsharp mask after Lanczos resize to restore crater crispness
Lanczos downsampling (NASA 2048 px → 756 px output) anti-aliases fine
crater rims and mare boundaries to a blur of ~1-2 px.  Apply Pillow's
UnsharpMask(radius=2, percent=160, threshold=2) immediately after resize
in both composite_full_moon and render_phase_closeup.  This restores the
perceived sharpness to match what the NASA source actually contains, and
brings crater detail in line with what a 52x optical zoom camera shows on
a clear night from the same location.  No AI or upscaling involved.

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
2026-05-03 18:31:24 +00:00
Claude 15ece6ff3f composite: switch to smooth synthetic atmospheric glow, eliminating foil artefact
The previous approach tried to preserve real sky-cam pixels near the moon and
darken them, but with a bright/hazy sky (thick clouds, full moon glow) the
cloud texture still bled through as the "wrinkled silver foil" look.

New approach in _atmospheric_sky_background():
- Sample the mean atmospheric colour from a ring at 1.15–1.8× moon radius.
- Scale it to a tasteful glow level (×0.35) — real colour, not raw brightness.
- Build a smooth quadratic radial gradient: halo colour at the disk edge,
  deep night-sky (R4 G6 B14) at 3× radius and beyond.

No raw sky-cam pixels appear in the background, so the result is texture-free
regardless of cloud cover or haze. Verified clean against both a normal frame
and a 2.5× brightened worst-case bright-sky simulation.

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
2026-05-03 18:10:27 +00:00
Claude 590e078a65 composite: replace bilateral-filter sky with atmospheric halo on dark background
The previous approach cropped the sky-cam frame tightly around the moon and
upscaled it as the composite background, causing cloud/haze texture to blow up
into a "wrinkled silver sheet" behind the moon disk.

New _atmospheric_sky_background() applies a radial blend:
- Inside 1.3× the moon radius the real sky is gamma-darkened (γ=1.6, ×0.65)
  so diffuse cloud texture collapses toward black while the bright atmospheric
  halo survives nearly intact.
- Beyond 2.2× the radius it transitions smoothly to a near-black night colour
  (R4 G6 B14), ensuring frame corners are properly dark rather than silver-grey.

Also removes the cv2 bilateral-filter dependency (only usage in the file).

https://claude.ai/code/session_01HuJ83KvMvshiY6HxJbtMsc
2026-05-03 18:05:16 +00:00
Outis 4d498cd54f Add files via upload 2026-05-03 12:26:18 -04:00
Outis 8905c60367 Merge pull request #69 from outis1one/claude/fix-sunrise-sunset-observer-BA0Iy
composite: use east frame background with bilateral filter at 70% zoom
2026-05-03 12:18:32 -04:00
Claude 6b46eb5128 composite: use east frame background with bilateral filter at 70% zoom
Switch monthly pipeline from render_phase_closeup (black background) to
composite_full_moon (east frame + NASA moon overlay) when an east frame
and detection are available.  Falls back to render_phase_closeup when
east verification is disabled.

Changes:
- composite_full_moon: bilateral filter (d=9, σ=75) on upscaled background
  to smooth pixelation artifacts before compositing the NASA moon
- composite_full_moon: caption now placed below the moon disk instead of
  overlapping it (paste_y + target_size + 12)
- run_phase: keep detection result (best_det) alongside best_frame
- _render_and_post: accept east_frame + detection, route to the right renderer
- Monthly pipeline uses moon_height_pct=0.70 for the east-frame composite

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-03 13:17:36 +00:00
Outis be27715fcb Merge pull request #68 from outis1one/claude/fix-sunrise-sunset-observer-BA0Iy
Claude/fix sunrise sunset observer ba0 iy
2026-05-02 08:54:10 -04:00
Claude 54f342224a docs: update test_last_full_moon.py README entry for full pipeline
Clarifies the script runs the complete production path including east
verification, and is equivalent to moon-phase-monthly.sh --phase full
--no-upload with a fixed output path.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:53:25 +00:00
Claude a470879d1e simplify test_last_full_moon.py: delegate to run_phase() with no_upload
Removes the bypass of east-frame verification — the script now runs the
complete production pipeline (dark-window filtering, moon detection on
east frames, NASA Dial-a-Moon fetch, render_phase_closeup) by calling
mpm.run_phase() with no_upload=True and a fixed test output path.

Retains the explicit sun_events_in_range() call as a regression check
for the bare-topos fix before the main pipeline runs.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:53:14 +00:00
Claude d8bf01f86f docs: update test_last_full_moon.py entry to match full image pipeline
Describes all six steps the script now performs: full moon lookup,
moon stats, sun events regression check, NASA fetch, composite render,
and output path.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:52:21 +00:00
Claude 985f4883a8 update test_last_full_moon.py to produce the full moon image
Now runs the complete production pipeline without east-frame verification:
find last full moon → fetch NASA Dial-a-Moon render → render_phase_closeup
→ test_last_full_moon_out.jpg with caption (phase, % lit, local time,
NASA attribution).

Also retains the sun_events_in_range() call as a regression check for
the sunrise_sunset() bare-topos fix.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:52:08 +00:00
Outis a17d4486f4 Merge pull request #67 from outis1one/claude/fix-sunrise-sunset-observer-BA0Iy
Claude/fix sunrise sunset observer ba0 iy
2026-05-02 08:49:31 -04:00
Claude 4f61589ca6 docs: document test_last_full_moon.py in README
Added to the Moon jobs section of Manual operations with a brief
description of what the script checks and when it's useful.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:48:50 +00:00
Claude aa4f699b43 add test_last_full_moon.py — smoke-test for moon phase + sun events
Finds the most recent full moon (within 35 days), prints illumination,
phase angle, alt/az, and parallactic angle, then calls sun_events_in_range()
for the surrounding day.  The sun_events call is the direct regression
path for the sunrise_sunset() observer fix (bare topos, not earth+topos).

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:48:39 +00:00
Claude 318af0dbf5 fix: pass bare topos to sunrise_sunset(), not earth+topos observer
skyfield's sunrise_sunset() internally computes ephemeris['earth'] + topos,
so passing the already-combined _observer caused a double-add ValueError.
Store _topos separately and use it only for almanac calls; _observer
(earth + topos) continues to be used for direct .at() observations.

https://claude.ai/code/session_01JieSeNQZ3X6fhsb11YyJrK
2026-05-02 12:43:03 +00:00
Outis 3bb17d0093 Merge pull request #66 from outis1one/claude/add-moon-image-locations-ACdGH
Claude/add moon image locations a cd gh
2026-05-02 08:13:39 -04:00
Claude 975c9cc2eb Use real sunset/sunrise for dark window; pick frame closest to exact phase
moon_phase.py: add sun_events_in_range() — returns actual sunset/sunrise
transitions via skyfield almanac, accurate to within a minute

moon_phase_monthly.py:
- _dark_moon_intervals(): replace sun-altitude threshold sampling with
  actual sunset/sunrise times; dark window = sunset + DARK_START_MIN to
  next sunrise; moon-above-horizon check still sampled every 10 min within
  each night; polar fallback if no sun events found
- run_phase(): sort dark-window frames by proximity to exact phase moment
  before scanning; first clear detection = the frame temporally closest to
  the moon being precisely full/at quarter, not just the first in time order
- Replace DARK_SKY_SUN_ALT_DEG with DARK_START_MIN (default 30 min)

sky-cam.conf: replace MOON_DARK_SKY_SUN_ALT_DEG with MOON_DARK_START_MIN=30;
update comments to explain ±24h window, sunset+30 start, closest-frame logic,
and how the 01:30 and 23:55 edge cases are handled

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 22:38:04 +00:00
Claude 3fc77ab75e Expand obs window to full dark+moon period; label with illumination%
moon_phase.py: add sun_altaz() to compute sun altitude for dark-sky check

moon_phase_monthly.py:
- Replace fixed 22:00-23:00 window with dynamic dark+moon intervals:
  sample every 10 min across ±24h of the phase moment, keep blocks where
  sun < DARK_SKY_SUN_ALT_DEG and moon > MIN_ALTITUDE — covers the full
  night the moon is actually visible in a dark sky regardless of month
- First east frame with quality >= MIN_QUALITY in that window wins
- Illumination% computed at the detection time and shown in the image
  caption and Mattermost message
- Remove OBS_TIME_H/M; add DARK_SKY_SUN_ALT_DEG config var

sky-cam.conf: replace MOON_OBS_TIME_LOCAL with MOON_DARK_SKY_SUN_ALT_DEG=-6
and explain the sun-altitude threshold options

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 22:32:16 +00:00
Claude a6989a9ea8 Simplify moon phase: binary go/no-go, parallactic angle rotation, no atmosphere overlay
- moon_composite.py: remove _make_atmosphere_layer() and all atmosphere
  parameters from render_phase_closeup(); add when_utc parameter and apply
  parallactic angle rotation so the NASA disk is oriented to match east's sky

- moon_phase_monthly.py: change obs time default to 22:00 (aligns with NASA
  hourly renders); scan east frames in 22:00-23:00 window; binary go/no-go
  (quality >= MIN_QUALITY = post, no clear shot = skip entirely); remove
  _atmosphere_opacity_from_quality(), ATMOSPHERE_BLUR, CLOUDY_POST_ENABLED

- sky-cam.conf: update MOON_OBS_TIME_LOCAL to 22:00, remove
  MOON_OBS_WINDOW_MIN, remove the atmospheric overlay and cloudy fallback
  sections and their config variables

- test_moon_composite.py: single clean test — fetch NASA for 22:00 UTC on
  2026-04-29, verify east frame quality, render with parallactic angle; no
  procedural fallback

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 22:27:34 +00:00
Claude 9e2852fd73 Use fixed obs time for NASA fetch and atmosphere check
Previous approach: scan a 3-day window, find best moon detection,
use that timestamp.  Problems: fuzzy composite (multi-day scan could
pick a frame far from actual full moon), no clear tie between the
NASA render and a specific observable moment.

New approach — MOON_OBS_TIME_LOCAL (default 22:30 local):
  On the night of the exact phase event, look at east frames in a
  ±MOON_OBS_WINDOW_MIN (default 30 min) window around the configured
  time.  The frame closest to that time determines atmosphere opacity;
  the same time (rounded to hour) drives the NASA Dial-a-Moon fetch.
  This gives one definitive moment per phase per month.

moon_phase_monthly.py:
  - PHASE_SPEC stripped to just post_delay + enabled_key (all window/
    illumination filtering removed — obs time is the only selector)
  - run_phase() replaced with obs-time logic; opacity derived from
    detect_moon quality on that single frame
  - MOON_FULL_POST_DELAY_DAYS / MOON_QUARTER_POST_DELAY_DAYS default
    changed to 1 (post morning after the phase, frames already on disk)

moon_composite.py:
  - atmosphere blur default: output_width//10 (192px) → output_width//20
    (96px) so cloud shapes survive the blur

sky-cam.conf:
  - MOON_OBS_TIME_LOCAL=22:30, MOON_OBS_WINDOW_MIN=30
  - Post delay defaults updated to 1

test_moon_composite.py:
  - Tries real NASA SVS Dial-a-Moon API first; procedural disc only as
    fallback if API unreachable
  - Runs detect_moon on the east frame to compute real opacity
  - Single output (test_composite_out.jpg)

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 22:03:57 +00:00
Outis da299f02ac Merge pull request #65 from outis1one/claude/add-moon-image-locations-ACdGH
Apply atmosphere overlay ON TOP of moon, add overcast fallback
2026-05-01 17:52:45 -04:00
Claude c09b872f52 Apply atmosphere overlay ON TOP of moon, add overcast fallback
The core mental model was wrong: clouds are between the observer and
the moon, so they occlude the disk — they don't sit behind it.

moon_composite.py:
  _make_east_sky_backdrop() → _make_atmosphere_layer()
  render_phase_closeup() pipeline is now:
    1. Black background
    2. NASA moon disk centred (correct phase / libration / shadows)
    3. East frame scaled + blurred → composited OVER the disk at
       atmosphere_opacity (0.0 = clear, 0.68 = heavy overcast)
  Parameters: east_sky_enabled/blur → atmosphere_opacity/blur

moon_phase_monthly.py:
  _atmosphere_opacity_from_quality() maps detection quality to opacity:
    quality >= 0.85 → 0.00 (clear)
    quality   0.70  → 0.20 (light haze)
    quality   0.55  → 0.40 (notable cloud, still detected)
    quality   None  → 0.68 (no detection, heavy overcast)

  Frame scan now tracks two lists:
    qualifying     — frames passing quality + illumination (existing)
    above_horizon  — frames where moon is up but detection failed

  When qualifying is empty and MOON_CLOUDY_POST_ENABLED=true, the
  above-horizon frame closest to the exact phase moment is used with
  opacity 0.45–0.68.  The month is always represented — full moon,
  first quarter, and third quarter each get a post even in cloudy
  months, showing the moon as a faint glow behind cloud.

sky-cam.conf:
  MOON_EAST_SKY_ENABLED/BLUR → MOON_ATMOSPHERE_BLUR (opacity is
  computed automatically from quality, not configured directly)
  New: MOON_CLOUDY_POST_ENABLED=true

test_moon_composite.py:
  Generates three outputs at opacity 0.00 / 0.20 / 0.65 so the
  full opacity range is visible in one test run.

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 21:51:42 +00:00
Outis c07469d4c3 Merge pull request #64 from outis1one/clDemoe/add-moon-image-locations-ACdGH
Replace annular cloud veil with full-frame east sky backdrop
2026-05-01 14:19:51 -04:00
Claude 1425a6e5f4 Replace annular cloud veil with full-frame east sky backdrop
The annular-ring veil approach sampled too small a region (38 px moon
in 3840×2160 gives a tiny annulus) and was invisible in practice.
More fundamentally, using the whole east sky is what "relayed to where
it was taken" actually means.

New approach — _make_east_sky_backdrop():
  Scale the full east camera frame to output size, apply GaussianBlur
  r = output_width // 6 (≈ 320 px at 1920 wide).  The blur erases RTSP
  artefacts, OSD overlays, and the wide-angle look while preserving real
  sky colour, cloud / haze gradients, and the dark ground silhouette.
  The NASA moon disk is pasted sharp on top.  The result reads as east
  photographed the moon through a telephoto with its actual sky that night.

  Clear dark sky → nearly black backdrop (same feel as before).
  Thin cloud cover → soft grey-blue haze behind the sharp moon.
  Heavy overcast → the moon detection would not qualify, so this case
    never reaches rendering.

Config rename: MOON_CLOUD_OVERLAY_* → MOON_EAST_SKY_ENABLED / _BLUR.
moon_phase_monthly.py: CLOUD_OVERLAY_* → EAST_SKY_*.
render_phase_closeup(): cloud_overlay_* params → east_sky_*.

test_moon_composite.py: replace full_moon_closeup.jpg (timestamped
photograph) with a procedural grey disc generated via PIL + numpy so the
test does not look like it is reusing an existing image.

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 18:17:54 +00:00
Outis 69329c4e07 Merge pull request #63 from outis1one/clDemoe/add-moon-image-locations-ACdGH
Fix missed raw draw.text in render_phase_closeup
2026-05-01 14:11:05 -04:00
Claude 5244fbb89b Fix missed raw draw.text in render_phase_closeup
The previous commit replaced the caption block in composite_full_moon
but missed render_phase_closeup because that block had no comment to
match the replace_all pattern. Both caption sites now go through
_draw_caption() so the Unicode / font fix applies everywhere.

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 18:10:25 +00:00
Outis 9f8d4f7393 Merge pull request #62 from outis1one/clDemoe/add-moon-image-locations-ACdGH
Fix UnicodeEncodeError in caption drawing
2026-05-01 14:08:41 -04:00
Claude b45ef3a791 Fix UnicodeEncodeError in caption drawing
The default PIL bitmap font only covers latin-1, so the em dash (U+2014)
in captions raised UnicodeEncodeError at runtime.

Add _load_font() which tries DejaVu Sans TTF from common system paths
(the fonts-dejavu package is already a listed dependency) and falls back
to the PIL default only when no TTF is found.  Add _draw_caption() which
wraps both the font load and the two-pass drop-shadow draw, and sanitises
the string for the bitmap fallback path so it never crashes.

Replace both raw draw.text caption blocks in composite_full_moon() and
render_phase_closeup() with _draw_caption().

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 18:07:53 +00:00
Outis 7e23066db6 Merge pull request #61 from outis1one/clDemoe/add-moon-image-locations-ACdGH
ClDemoe/add moon image locations a cd gh
2026-05-01 14:05:39 -04:00
Claude 09fda8d8af Add smoke-test script for cloud-veil composite
test_moon_composite.py uses the existing repo sample frames
(21-07-00.jpg east frame with thin cloud cover + full_moon_closeup.jpg
as NASA render stand-in) to produce test_composite_out.jpg without
needing a live NASA API call or moon detection run.

Run: python3 test_moon_composite.py

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 17:16:50 +00:00
Claude 3ededd68b8 Add per-event NASA moon images with east-sky cloud veil
Three changes driven by the same goal: make each monthly moon post
look like east captured it at that exact moment.

Tighter illumination windows (±4% of target phase):
  Full moon:   95% → 96–100%  (was a 5-point band; now hugs exact full)
  Quarters:    40–65% → 46–54%  (was a 25-point band; now ±4% of 50%)
This ensures the NASA Dial-a-Moon render timestamp is pulled within
4 percentage points of the true phase, making the fetched image
genuinely represent that night's moon.  One fresh fetch per event,
~3/month, cached by hour — never reused across months.

Atmospheric cloud veil from east's surrounding sky:
  _extract_cloud_veil() samples the annular sky region just outside
  east's moon disk (2×–5× radius), scales it to the output frame,
  blurs heavily (GaussianBlur r≈output_width/10) so it reads as haze
  rather than an upscaled photo, then blends it over the NASA composite
  at an opacity proportional to sky brightness:
    sky < 5% mean brightness → no veil (clear dark night)
    sky ~10%                 → ~17% veil (thin haze / airglow)
    sky ≥ 20%                → 40% veil (max, MOON_CLOUD_OVERLAY_MAX_OPACITY)
  After the veil pass the NASA moon disk is re-pasted sharply so the
  haze sits naturally behind the crisp lunar surface.
  This is the honest answer to "east can't capture high-res clouds":
  east's real atmospheric fingerprint becomes the veil texture.

New sky-cam.conf keys:
  MOON_CLOUD_OVERLAY_ENABLED=true
  MOON_CLOUD_OVERLAY_MAX_OPACITY=0.40
  #MOON_CLOUD_OVERLAY_BLUR=0  (0 = auto)

https://claude.ai/code/session_01HkTxpNSTWtViZzxbrbKytR
2026-05-01 17:07:16 +00:00
Outis ebba2b3ae3 Merge pull request #60 from outis1one/clDemoe/digital-zoom-moon-capture-DprtQ
Switch monthly phase close-ups to NASA SVS Dial-a-Moon at fullscreen
2026-05-01 09:39:13 -04:00
Outis cbffe426c4 Merge pull request #59 from outis1one/clDemoe/fix-video-deletion-error-624Gp
Fix afade: bc omits leading zero for values < 1 (.850 → 0.850)
2026-05-01 09:38:52 -04:00
Claude 28c3c1dc63 Switch monthly phase close-ups to NASA SVS Dial-a-Moon at fullscreen
The previous east-flavored composite (tight-crop east region + lunar
texture overlay) was honest but visually limited: 38-px source moon, no
real terminator shadows on quarters, and a faint upscaled-halo
background that was less compelling than just a clean lunar render.

New flow:
- East stays the witness (verifies the moon was visible during the
  collection window) and supplies the timestamp.
- moon_dialamoon.py fetches the NASA SVS Dial-a-Moon render for that
  exact UTC hour. Free, public-domain, real-physics: correct phase,
  libration, and crater shadows for any timestamp.
- moon_composite.render_phase_closeup() places that render at ~92% of
  frame height on a 1920x1080 black background -- the long-telephoto
  look the user asked for.
- One API call per phase event (~36/year), cached forever in
  moon-ref/dialamoon/.

Quarter moons now show real 3D crater shadows along the terminator,
which the prior algorithmic phase-shadow couldn't simulate from a
full-moon reference.

Adds MOON_REQUIRE_EAST_VERIFY=true|false toggle so the user can choose
"only post when east saw it" (default, current behavior) vs "post every
cycle regardless of weather over east."

Drops the install-time lunar reference download (no longer needed) and
the now-unused per-phase phase-shadow path stays in moon_composite.py
for reference / future reuse.

https://claude.ai/code/session_015PBVDESC3KLMbq1LpA6qLn
2026-05-01 11:54:46 +00:00
Claude ed8982da0e Fix afade: bc omits leading zero for values < 1 (.850 → 0.850)
fade_dur = SUNRISE_TARGET_SECS * 0.085 = 0.850 at the default 10s target.
bc outputs .850 without a leading zero, which ffmpeg's afade filter rejects
with "Unable to parse option value .850 as duration". Pipe bc output through
sed to prepend the zero when the value starts with '.'.

https://claude.ai/code/session_01DANuzLCLhhQ7Li12RTcswY
2026-05-01 05:09:57 +00:00
Outis b0d74a5837 Merge pull request #58 from outis1one/clDemoe/fix-video-deletion-error-624Gp
Add ambient chunk as 2nd Demoio fallback; fix capture service exit-cod…
2026-04-30 18:02:33 -04:00
Outis 7500a94c7d Merge pull request #57 from outis1one/clDemoe/digital-zoom-moon-capture-DprtQ
Add nightly moon-track timelapse and monthly moon-phase composites
2026-04-30 18:02:04 -04:00
Claude 61e9e4d0be Add ambient chunk as 2nd audio fallback; fix capture service exit-code bug
daily_sunrise_video.sh:
- Insert continuous ambient recording extract as 2nd fallback (after today's
  scheduled sunrise audio, before live RTSP).  Finds the chunk file in
  AUDIO_DIR/<cam>/<date>/ whose start time is the latest one at or before
  sunrise, then ffmpeg-copies SUNRISE_TARGET_SECS centred on sunrise_sec.
- Renumber remaining fallbacks: live RTSP → 3rd, yesterday → 4th, library → 5th.

sunrise-audio-capture.sh:
- Fix: retention find pipeline could exit non-zero (directory not yet created
  or permission error) and with set -euo pipefail cause the service to report
  status=1/FAILURE even after a successful capture.  Guard with [ -d ] and
  add || true so a retention failure never masks a successful recording.

https://claude.ai/code/session_01DANuzLCLhhQ7Li12RTcswY
2026-04-30 19:47:53 +00:00
Outis 31abda890b Merge pull request #56 from outis1one/claude/fix-video-deletion-error-624Gp
Claude/fix video deletion error 624 gp
2026-04-30 08:47:56 -04:00
Claude 65b8caf7f9 Reorder audio fallback chain: today → live RTSP → yesterday → library
Moves live RTSP capture to 2nd position so current ambient sound is
preferred over a day-old recording when today's scheduled capture is missing.

https://claude.ai/code/session_01DANuzLCLhhQ7Li12RTcswY
2026-04-30 11:53:57 +00:00
Claude c2d4d97361 Fix audio: live RTSP fallback + mix retry + journal in ntfy; overlay at 15%
- daily_sunrise_video.sh: add live RTSP capture as final fallback in production
  audio selection (fires when today, yesterday, and library all miss)
- On audio mix failure, retry once with a fresh live RTSP capture before
  giving up — handles corrupt/incompatible pre-recorded files
- When mix still fails after retry, append last 30 lines of
  sky-cam-audio-capture.service journal to the ntfy notification body
- Move sunrise-time text overlay from 5% to 15% above the bottom edge

https://claude.ai/code/session_01DANuzLCLhhQ7Li12RTcswY
2026-04-30 11:50:02 +00:00
Claude 5fb7ff09a3 Add nightly moon-track timelapse and monthly moon-phase composites
Two new jobs operate on the SUNRISE_CAM, sharing three Python helpers
(moon_phase, moon_detect, moon_composite) and one cached lunar texture:

- moon-track.sh: nightly batch detects the moon in each east frame,
  crops a 480x480 box around it, stitches into an mp4 that holds the
  moon roughly centred while clouds and stars drift past.

- moon-phase-monthly.sh: daily check that runs whichever phase composite
  is due that day. Handles full moon (posts D+3), first quarter (D+2,
  best-effort due to daytime-only geometry from east), and third quarter
  (D+2). Picks the frame closest in time to the exact phase moment that
  meets quality / altitude / illumination thresholds, then composites
  the cached lunar texture into it -- sky/halo/parallactic-angle/timing
  real from east, surface detail borrowed from the reference image.

Honest-by-design: a 38-px white blob from a wide-field IP camera cannot
be enhanced into crater detail by software. The composite makes the
borrowing explicit and constrains everything else (when, where, sky,
orientation) to match what east actually saw.

install.sh now downloads the skyfield ephemeris (de421.bsp) and the
default lunar reference (Wikipedia CC BY-SA full-moon photo) on first
run. Both can be overridden via .env.

https://claude.ai/code/session_015PBVDESC3KLMbq1LpA6qLn
2026-04-30 11:40:11 +00:00
Outis 03ebb53754 Add files via upload 2026-04-30 03:07:22 -04:00
Outis 69b9056276 Add files via upload 2026-04-30 02:37:25 -04:00
Outis 499bafdcc2 Merge pull request #55 from outis1one/claude/comment-sunrise-overlay-9LvlR
Trim weather-tag vocabulary to audio-relevant precipitation only
2026-04-29 14:58:11 -04:00
Claude 5810ab0194 Trim weather-tag vocabulary to audio-relevant precipitation only
Drops clear/cloudy/fog/windy and the wind-speed override — those
conditions sound the same on the recordings, so they don't earn a tag.
Also renames "rainshower" → "rainstorm" and rebalances the rain
mapping so 503/504/522 (extreme + heavy showers) get the storm tag.

Final vocabulary: thunderstorm, rain, rainstorm, snow, snowstorm.
Anything else falls through to the un-tagged filename.
2026-04-29 18:55:59 +00:00
Outis 5d00ac954f Merge pull request #54 from outis1one/claude/comment-sunrise-overlay-9LvlR
Claude/comment sunrise overlay 9 lvl r
2026-04-29 14:51:11 -04:00